Częstym wymogiem w GIS jest zastosowanie narzędzia przetwarzania do wielu plików lub zastosowanie procesu dla wielu funkcji w jednym pliku do innego pliku.
Wiele z tych operacji jest krępująco równoległych, ponieważ wyniki obliczeń w żaden sposób nie wpływają na żadną inną operację w pętli. Nie tylko to, ale często pliki wejściowe są różne.
Klasycznym przykładem jest kafelkowanie plików kształtów w stosunku do plików zawierających wielokąty w celu przycięcia ich.
Oto (przetestowana) klasyczna metoda proceduralna umożliwiająca osiągnięcie tego w skrypcie Python dla QGIS. (fyi wyjściowe pliki pamięci tymczasowej do prawdziwych plików ponad połowę czasu na przetwarzanie moich plików testowych)
import processing
import os
input_file="/path/to/input_file.shp"
clip_polygons_file="/path/to/polygon_file.shp"
output_folder="/tmp/test/"
input_layer = QgsVectorLayer(input_file, "input file", "ogr")
QgsMapLayerRegistry.instance().addMapLayer(input_layer)
tile_layer = QgsVectorLayer(clip_polygons_file, "clip_polys", "ogr")
QgsMapLayerRegistry.instance().addMapLayer(tile_layer)
tile_layer_dp=input_layer.dataProvider()
EPSG_code=int(tile_layer_dp.crs().authid().split(":")[1])
tile_no=0
clipping_polygons = tile_layer.getFeatures()
for clipping_polygon in clipping_polygons:
print "Tile no: "+str(tile_no)
tile_no+=1
geom = clipping_polygon.geometry()
clip_layer=QgsVectorLayer("Polygon?crs=epsg:"+str(EPSG_code)+\
"&field=id:integer&index=yes","clip_polygon", "memory")
clip_layer_dp = clip_layer.dataProvider()
clip_layer.startEditing()
clip_layer_feature = QgsFeature()
clip_layer_feature.setGeometry(geom)
(res, outFeats) = clip_layer_dp.addFeatures([clip_layer_feature])
clip_layer.commitChanges()
clip_file = os.path.join(output_folder,"tile_"+str(tile_no)+".shp")
write_error = QgsVectorFileWriter.writeAsVectorFormat(clip_layer, \
clip_file, "system", \
QgsCoordinateReferenceSystem(EPSG_code), "ESRI Shapefile")
QgsMapLayerRegistry.instance().addMapLayer(clip_layer)
output_file = os.path.join(output_folder,str(tile_no)+".shp")
processing.runalg("qgis:clip", input_file, clip_file, output_file)
QgsMapLayerRegistry.instance().removeMapLayer(clip_layer.id())
Byłoby dobrze, gdyby mój plik wejściowy miał 2 GB, a plik przycinający wielokąt zawiera ponad 400 wielokątów. Wynikowy proces trwa ponad tydzień na mojej czterordzeniowej maszynie. Przez cały czas trzy rdzenie są na biegu jałowym.
Rozwiązaniem, które mam w głowie, jest wyeksportowanie procesu do plików skryptów i uruchomienie ich asynchronicznie, na przykład przy użyciu równoległego GNU. Jednak szkoda, że trzeba zrezygnować z QGIS w rozwiązaniu specyficznym dla systemu operacyjnego, zamiast używać czegoś natywnego dla Pythona QGIS. Więc moje pytanie brzmi:
Czy mogę równolegle zawstydzać równoległe operacje geograficzne natywnie w Pythonie QGIS?
Jeśli nie, to może ktoś już ma kod, aby wysłać tego rodzaju pracę do asynchronicznych skryptów powłoki?