Ich mache einige Zahlen in einem Raster mit arcpy
Knirschen und möchten das multiprocessing
-Paket verwenden, um die Dinge zu beschleunigen. Grundsätzlich muss ich eine Liste von Tupeln durchlaufen, einige Rasterberechnungen mit jedem Tupel durchführen und einige Ausgaben in Dateien schreiben. Meine Eingaben bestehen aus einem Datenraster (Bathymetrie), einem Raster, das Zonen definiert, und einem Tupel aus zwei Schwimmern (Wasseroberflächenhöhe, Tiefe). Meine Prozedur besteht aus einer Funktion computeplane
, die ein Tupel nimmt und eine Reihe von Rasterberechnungen ausführt, um fünf Raster zu erzeugen (total, littoral, surface, subsurface, profundal) und dann die Funktion processtable
für jedes dieser Raster aufruft, um Werte in a zu schreiben DBF mit arcpy.sa.ZonalStatisticsAsTable
, fügen Sie einige Felder mit arcpy.AddField_management
, konvertieren Sie die DBF in eine CSV mit arcpy.TableToTable_conversion
, und löschen Sie schließlich die DBF-Datei mit arcpy.Delete_management
.arcpy + multiprocessing: Fehler: konnte Raster-Datensatz nicht speichern
Basiert auf etwas, ich habe meinen Code in main()
so eingewickelt, dass multiprocessing.Pool
angeblich nett spielt. Ich benutze main()
, um den Satz von Tupeln und pool.map
zu erstellen, um das Multiprocessing zu machen. Ich verwende das Paket tempfile
, um Namen für die dbf-Datei auszuwählen, um Namenskonflikte zu vermeiden. Die CSV-Dateinamen stehen garantiert nicht in Konflikt mit den anderen Threads.
Ich habe meinen Code mit einer for-Schleife getestet und es funktioniert gut, aber wenn ich versuche pool.map
ich zu verwenden
RuntimeError: ERROR 010240: Could not save raster dataset to C:\Users\Michael\AppData\Local\ESRI\Desktop10.4\SpatialAnalyst\lesst_ras with output format GRID.
Was hier geschieht? Dieser Fehler wird nicht in der nicht-multiprocess-Version des Codes angezeigt, und ich schreibe die Raster nirgendwo heraus --- dann wieder weiß ich nicht, wie arcpy
mit den Zwischenrastern beschäftigt ist (ich sicher nicht Ich denke, es hält sie im Gedächtnis - sie sind zu groß. Muss ich der arcpy
etwas über die Art, wie es die Rasterberechnungen behandelt, damit Multiprocessing funktioniert? Ich habe meine Python-Datei unten eingefügt.
import arcpy
arcpy.CheckOutExtension("Spatial")
import arcpy.sa
import numpy
import multiprocessing
import tempfile
bathymetry_path = r'C:/GIS workspace/RRE/habitat.gdb/bathymetry_NGVD_meters'
zones_path = r'C:/GIS workspace/RRE/habitat.gdb/markerzones_meters'
table_folder = r'C:/GIS workspace/RRE/zonetables'
bathymetry = arcpy.sa.Raster(bathymetry_path)
zones = arcpy.sa.Raster(zones_path)
def processtable(raster_obj, zone_file, w, z, out_folder, out_file):
temp_name = "/" + next(tempfile._get_candidate_names()) + ".dbf"
arcpy.sa.ZonalStatisticsAsTable(zone_file, 'VALUE', raster_obj, out_folder + temp_name, "DATA", "SUM")
arcpy.AddField_management(out_folder + temp_name, "wse", 'TEXT')
arcpy.AddField_management(out_folder + temp_name, "z", 'TEXT')
arcpy.CalculateField_management(out_folder + temp_name, "wse", "'" + str(w) + "'", "PYTHON")
arcpy.CalculateField_management(out_folder + temp_name, "z", "'" + str(z) + "'", "PYTHON")
arcpy.TableToTable_conversion(out_folder + temp_name, out_folder, out_file)
arcpy.Delete_management(out_folder + temp_name)
def computeplane(wsedepth):
wse = wsedepth[0]
depth = wsedepth[1]
total = bathymetry < depth
littoral = total & ((wse - bathymetry) < 2)
surface = total & ~(littoral) & ((total + wse - depth) < (total + 2))
profundal = total & ((total + wse - depth) > (total + 5))
subsurface = total & ~(profundal | surface | littoral)
# zonal statistics table names
total_name = 'total_w' + str(wse) + '_z' + str(depth) + '.csv'
littoral_name = 'littoral_w' + str(wse) + '_z' + str(depth) + '.csv'
surface_name = 'surface_w' + str(wse) + '_z' + str(depth) + '.csv'
subsurface_name = 'subsurface_w' + str(wse) + '_z' + str(depth) + '.csv'
profundal_name = 'profundal_w' + str(wse) + '_z' + str(depth) + '.csv'
# compute zonal statistics
processtable(total, zones, wse, depth, table_folder, total_name)
processtable(littoral, zones, wse, depth, table_folder, littoral_name)
processtable(surface, zones, wse, depth, table_folder, surface_name)
processtable(profundal, zones, wse, depth, table_folder, profundal_name)
processtable(subsurface, zones, wse, depth, table_folder, subsurface_name)
def main():
watersurface = numpy.arange(-15.8, 2.7, 0.1)
# take small subset of the tuples: watersurface[33:34]
wsedepths = [(watersurface[x], watersurface[y]) for x in range(watersurface.size)[33:34] for y in range(watersurface[0:x+1].size)]
pool = multiprocessing.Pool()
pool.map(computeplane, wsedepths)
pool.close()
pool.join()
if __name__ == '__main__':
main()
UPDATE
Einige mehr sleuthing zeigt, dass dies nicht so sehr mit der Art und Weise multiprocessing
Problem als ein Problem ist, dass ArcGIS Rasterverarbeitung der Fall ist. Rasteralgebra-Ergebnisse werden in Dateien im Standardarbeitsbereich geschrieben. In meinem Fall hatte ich keinen Ordner angegeben, daher schrieb arcpy
die Raster in einen AppData-Ordner. ArcGIS verwendet Basistypen wie Lessth, Lessth1 usw. basierend auf dem, was Ihr Algebraausdruck ist. Da ich keinen Arbeitsbereich angegeben habe, haben alle multiprocessing
Threads in diesen Ordner geschrieben. Während ein einzelner arcpy
Prozess Namen verfolgen kann, versuchen die mehreren Prozesse alle die gleichen Rasternamen zu schreiben und stoßen auf die Sperren des anderen Prozesses.
Ich habe versucht, eine zufälligen Arbeitsplatz (Datei GDB) zu Beginn der computeplane
zu schaffen und es dann am Ende zu löschen, aber arcpy
entbindet in der Regel nicht die Sperre in einer angemessenen Art und Weise und der Prozess abstürzt, auf der Delete-Anweisung. Ich bin mir also nicht sicher, wie es weitergehen soll.