Python arcpy&x2B;多处理:错误:无法保存光栅数据集
我正在使用Python arcpy&x2B;多处理:错误:无法保存光栅数据集,python,python-multiprocessing,arcpy,Python,Python Multiprocessing,Arcpy,我正在使用arcpy对光栅进行数字运算,并希望使用多处理软件包加快运算速度。基本上,我需要循环遍历一个元组列表,使用每个元组进行一些光栅计算,并将一些输出写入文件。我的输入包括一个数据光栅(测深)、一个定义分区的光栅和一个由两个浮标组成的元组(水面高程、深度)。我的过程包括一个函数computeplane,它获取一个元组并运行一系列光栅计算,以生成五个光栅(总计、沿岸、表面、地下、深部),然后为每个光栅调用函数processtable,使用arcpy.sa.ZonalStatisticsAsTa
arcpy
对光栅进行数字运算,并希望使用多处理
软件包加快运算速度。基本上,我需要循环遍历一个元组列表,使用每个元组进行一些光栅计算,并将一些输出写入文件。我的输入包括一个数据光栅(测深)、一个定义分区的光栅和一个由两个浮标组成的元组(水面高程、深度)。我的过程包括一个函数computeplane
,它获取一个元组并运行一系列光栅计算,以生成五个光栅(总计、沿岸、表面、地下、深部),然后为每个光栅调用函数processtable
,使用arcpy.sa.ZonalStatisticsAsTable
将值写入dbf,使用arcpy.AddField\u management
添加一些字段,使用arcpy.tableto\u转换将dbf转换为csv,最后使用arcpy.delete\u management
删除dbf文件
基于一些,我已经将代码包装在main()
中,这样multiprocessing.Pool
应该会玩得很好。我使用main()
创建元组集,并使用pool.map
进行多处理。我使用tempfile
包为dbf文件选择名称,以避免名称冲突;csv文件名保证不会与其他线程冲突
我已经用for循环测试了我的代码,它运行得很好,但是当我尝试使用pool.map
时,我得到了
运行时错误:错误010240:无法将光栅数据集保存到
C:\Users\Michael\AppData\Local\ESRI\Desktop10.4\spacealanalyst\lesst\u ras
使用输出格式网格
这里发生了什么?这个错误不会出现在非多进程版本的代码中,而且我也不会在任何地方写出光栅---再说一遍,我不知道arcpy
如何处理中间光栅(我当然不认为它会将它们保存在内存中---它们太大)。我是否需要告诉arcpy它处理光栅计算的方式,以便进行多处理?我在下面包含了我的python文件
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()
导入arcpy
arcpy.CheckOutExtension(“空间”)
导入arcpy.sa
进口numpy
导入多处理
导入临时文件
水深测量路径=r'C:/GIS工作区/RRE/habitat.gdb/Depthymetry\u NGVD\u meters'
zones\u path=r'C:/GIS workspace/RRE/habitat.gdb/markerzones\u meters'
表_folder=r'C:/GIS工作区/RRE/zonetables'
测深=arcpy.sa.光栅(测深路径)
zones=arcpy.sa.graster(zones\u路径)
def processtable(光栅对象、分区文件、w、z、输出文件夹、输出文件):
temp_name=“/”+下一步(tempfile.\u获取_候选人_name())+“.dbf”
arcpy.sa.ZonalStatisticsTable(分区文件“值”、光栅对象、输出文件夹+临时名称、“数据”、“总和”)
arcpy.AddField\u管理(out\u文件夹+临时名称,“wse”,“TEXT”)
arcpy.AddField_管理(out_文件夹+临时名称,“z”,“TEXT”)
arcpy.CalculateField_管理(out_文件夹+临时名称,“wse”、“'”、“+str(w)+”、“PYTHON”)
arcpy.CalculateField_管理(out_文件夹+临时名称,“z”、“'”+str(z)+“PYTHON”)
arcpy.TableToTable\u转换(out\u文件夹+临时名称、out\u文件夹、out\u文件)
arcpy.Delete_管理(out_文件夹+临时名称)
def计算平面(wsedepth):
wse=wsedepth[0]
深度=wsedepth[1]
总深度=水深<深度
滨海=总深度((wse-水深测量)<2)
表面=总面积&~(沿岸)&((总面积+wse-深度)<(总面积+2))
深度=总深度((总深度+wse-深度)>(总深度+5))
地下=总面积和(深部|表面|沿岸)
#分区统计表名称
total_name='total_w'+str(wse)+''u z'+str(深度)+'.csv'
滨海_名称='滨海_w'+str(wse)+'_z'+str(深度)+'.csv'
surface_name='surface_w'+str(wse)+''uz'+str(depth)+'.csv'
地下_名称='地下_w'+str(wse)+'_z'+str(深度)+'.csv'
深度名称='profundal_w'+str(wse)+''uz'+str(深度)+'.csv'
#计算分区统计
processtable(总计、分区、wse、深度、表格文件夹、总计名称)
processtable(海岸、分区、wse、深度、表格文件夹、海岸名称)
processtable(曲面、分区、wse、深度、表格文件夹、曲面名称)
processtable(深表、分区、wse、深度、表文件夹、深表名称)
processtable(地下、分区、wse、深度、表\u文件夹、地下\u名称)
def main():
水面=numpy.arange(-15.8,2.7,0.1)
#取元组的小子集:watersurface[33:34]
wsedepths=[(watersurface[x],watersurface[y])表示范围内的x(watersurface.size)[33:34]表示范围内的y(watersurface[0:x+1].size]
池=多处理。池()
pool.map(computeplane、wsedeths)
pool.close()
pool.join()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
更新
进一步调查表明,这与其说是一个多处理问题,不如说是ArcGIS进行光栅处理的方式问题。光栅代数结果将写入默认工作区中的文件;在我的例子中,我没有指定文件夹,因此arcpy
正在将光栅写入某个AppData文件夹。ArcGIS根据代数表达式使用基本名称,如Lessth、Lessth_1等。因为我没有指定工作区,所以所有的多处理
线程都在写入这个文件夹。虽然单个arcpy
进程可以跟踪名称,但多个进程都试图写入相同的光栅名称,并撞到另一个进程的锁
我尝试在computeplane
的开头创建一个随机工作区(文件gdb),然后在结尾删除它,但是arcpy
通常不会及时释放其锁,并且进程会在delete语句上崩溃。因此,我不确定如何继续。好吧,错误010240的解决方案是使用arcpy.gp.RasterCalculator_sa
函数而不是arcpy.sa
来编写
def computeplane_multi(processList):
pool = Pool(processes=4, maxtasksperchild=10)
jobs= {}
for item in processList:
jobs[item[0]] = pool.apply_async(computeplane, [x for x in item])
for item,result in jobs.items():
try:
result = result.get()
except Exception as e:
print(e)
pool.close()
pool.join()
import arcpy
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'
def computeplane(bathymetry_path,zones_path,wsedepth):
def processtable(raster_obj, zones_path, w, z, out_folder, out_file):
zone_file = arcpy.sa.Raster(zones_path)
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)
bathymetry = arcpy.sa.Raster(bathymetry_path)
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_path, wse, depth, table_folder, total_name)
processtable(littoral, zones_path, wse, depth, table_folder, littoral_name)
processtable(surface, zones_path, wse, depth, table_folder, surface_name)
processtable(profundal, zones_path, wse, depth, table_folder, profundal_name)
processtable(subsurface, zones_path, wse, depth, table_folder, subsurface_name)
print('point processed : {},{}'.format(wsedepth[0],wsedepth[1]))
def computeplane_multi(processList):
pool = Pool(processes=4, maxtasksperchild=10)
jobs= {}
for item in processList:
jobs[item[0]] = pool.apply_async(computeplane, [x for x in item])
for item,result in jobs.items():
try:
result = result.get()
except Exception as e:
print(e)
pool.close()
pool.join()
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)]
processList = []
for i in wsedepths:
processList.append((bathymetry_path,zones_path,i))
computeplane_multi(processList)
if __name__ == '__main__':
main()