Description
As of version 1.1.0 stac items are handeled in a synchronized way. This is fine for a few items, but has a long runtime with over hundreds of items.
I use our own LGLN script to build the catalog up from collections and items, calling our own function for the heavy lifting, normalizing and then save the catalog in the end.
With pythons concurrent lib, I was able to fasten up the item creation from tiff files with the ThreadPoolExecutor, but having trouble with using a ProcessPoolExecutor, which would be the right way to do it, cause the task is pretty much just cpu-bound, not I/O-bound in any way.
I can see a 400% increase in item creation speed with 16 processes spawned instead of one, but have to comment out the save method in the end, which then generated nothing.
Unfortunately, the catalog.save method does not wait at all for the catalog.add_item method to return and so tries to build a dictionary from an empty list, which results in an error.
To circumvent this, it would be really great, if pystac itself internally could handle the creation of items and adding to the catalog asynchronously, maybe with an extra parameter, to be synchronious handling still be the default, because "it just works".
def addImageItemsToCatalog(imageList, catalog):
"""multithreaded execution inspired by:
https://stackoverflow.com/questions/21143162/python-wait-on-all-of-concurrent-futures-threadpoolexecutors-futures
Performance increase was measured to be around 100%, measured with 93 stac items in 2 different catalogs,
compared to singlethreaded.
Could be further increased with multiprocess implementation (e.g. use "ProcessPoolExecutor" instead),
but a way to have the "catalog.save" method be waiting on the execution has to be found, otherwise
pyStac will fail.
"""
executor = concurrent.futures.ProcessPoolExecutor(MULTI_THREAD_SWEET_SPOT)
futures = [executor.submit(writeImageFileItems, imageFile, catalog) for imageFile in imageList]
concurrent.futures.wait(futures, timeout=None, return_when=ALL_COMPLETED)
# VVV this is done on the main thread, without waiting, which crashes :(
catalog.normalize_hrefs("generated/dop")
print("Saving catalog to " + catalog.get_self_href())
catalog.save(catalog_type=pystac.CatalogType.SELF_CONTAINED)
The resulting error would be the following, which I think is clear to me, because .save() does not wait for anything to be in there:
Traceback (most recent call last):
File "C:\dev\repo\task-3d-2.0\prototypes\dopCatalogBuilder\main.py", line 9, in <module>
main()
File "C:\dev\repo\task-3d-2.0\prototypes\dopCatalogBuilder\main.py", line 5, in main
dopCatalogBuilder.build()
File "C:\dev\repo\task-3d-2.0\prototypes\dopCatalogBuilder\dopCatalogBuilder.py", line 100, in build
dop_catalog = createCatalogFromAreaDictionary(dopImages, subcatalogs, catalogTitle="test raster Orthophotos",
File "C:\dev\repo\task-3d-2.0\prototypes\dopCatalogBuilder\dopCatalogBuilder.py", line 114, in createCatalogFromAreaDictionary
addImageItemsToCatalog(images, dopCatalog)
File "C:\dev\repo\task-3d-2.0\prototypes\dopCatalogBuilder\dopCatalogBuilder.py", line 133, in addImageItemsToCatalog
catalog.save(catalog_type=pystac.CatalogType.SELF_CONTAINED)
File "C:\Users\dev\anaconda3\envs\catalogBuilder\lib\site-packages\pystac\catalog.py", line 753, in save
child.save()
File "C:\Users\dev\anaconda3\envs\catalogBuilder\lib\site-packages\pystac\catalog.py", line 783, in save
self.save_object(
File "C:\Users\dev\anaconda3\envs\catalogBuilder\lib\site-packages\pystac\stac_object.py", line 341, in save_object
stac_io.save_json(dest_href, self.to_dict(include_self_link=include_self_link))
File "C:\Users\dev\anaconda3\envs\catalogBuilder\lib\site-packages\pystac\collection.py", line 520, in to_dict
d["extent"] = self.extent.to_dict()
AttributeError: 'list' object has no attribute 'to_dict'