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()