如何平行剪辑栅格?

时间:2015-11-11 02:45:11

标签: python multiprocessing raster pool arcpy

我正在研究一个多处理示例(An introduction to parallel programming)。我修改了Pool Class示例以满足我的特定需求 - 用一个并行的研究区域多边形剪切一堆栅格。从好的方面来说,脚本完成并打印“Processing Complete”。在消极方面,没有产生输出。我怀疑我在`pool.apply_async'函数中有一些程序错误。为什么这个脚本没有产生结果?

import arcpy, os
import multiprocessing as mp

arcpy.env.workspace = r'F:\temp\inws'
outws_utm11 = r'F:\temp\outws'
clipper_utm11 = r'F:\temp\some_polygon.shp'

rasters = arcpy.ListRasters()

pool = mp.Pool(processes=4)

def clip_raster(clipper, outws, raster):
        arcpy.Clip_management(raster, "#", os.path.join(outws, raster), clipper, nodata_value = 0, clipping_geometry = "ClippingGeometry")

[pool.apply_async(clip_raster, args=(clipper_utm11,outws_utm11, ras)) for ras in rasters]

print "Processing complete."

2 个答案:

答案 0 :(得分:2)

apply_async函数在工作进程中启动函数,但在函数完成之前不会阻塞。您让主流程完成并退出,而不是等待工人完成。这会导致它们被杀死,这可能会在它们创建输出之前被破坏。

由于您只是将同一功能应用于rasters列表中的所有项目,因此您应该考虑使用pool.map。它将接受函数名和可迭代对象作为其参数,并在列表中的每个项上调用该函数。所有这些函数调用都将在池中的工作进程中进行。但pool.map函数的一个警告是,传递它的函数对象必须只接受一个参数:列表中的项。我看到您的clip_rasters函数使用了其他几个参数,因此在下面的示例中,我使用functools.partial创建了clip_raster的新版本始终< / em>包含前两个参数。这个绑定了clipper_utm11outws_utm11的新功能现在可以与pool.map一起使用。

import arcpy, os
import functools
import multiprocessing as mp

arcpy.env.workspace = r'F:\temp\inws'
outws_utm11 = r'F:\temp\outws'
clipper_utm11 = r'F:\temp\some_polygon.shp'

rasters = arcpy.ListRasters()

pool = mp.Pool(processes=4)

def clip_raster(clipper, outws, raster):
        arcpy.Clip_management(raster, "#", os.path.join(outws, raster), clipper, nodata_value = 0, clipping_geometry = "ClippingGeometry")

bound_clip_raster = functools.partial(clip_raster, clipper_utm11, outws_utm11)
results = pool.map(bound_clip_raster, rasters)

print "Processing complete."

此代码会针对bound_clip_raster列表中的每个项目调用rasters函数,包括clipper_utm11outws_utm11。所有结果都将在名为results的列表中提供,并且对pool.map的调用是阻塞的,因此主进程将等到所有工作人员完成后再退出。

如果由于某些奇怪的原因,您打算使用apply_async,那么您需要在脚本的末尾添加一些代码才能使用AsyncResult对象& #39;阻止主进程直到它们完成的相关方法,例如wait(),或通过调用ready()轮询完成循环。但是你真的应该使用pool.map这个用例。这就是它的目的。

答案 1 :(得分:2)

我已经回答了一个可能对您也有用的问题。在这里看看:question

有一些好的做法,例如像您所做的那样将所有内容放入函数中,但必须要有一个main()函数并被

阻止
if __name__ == '__main__':
    main()

另一件事是此函数调用我在您的代码中插入的pool.apply_assync。

还进行了一些修改,因此您可以尝试一下,我已经测试过了,并且对我有用:

import arcpy, os
from multiprocessing import Pool

arcpy.env.workspace = r'C:\Gis\lab_geo\2236622'
outws_utm11 = r'C:\Gis\lab_geo\2236622\outs'
clipper_utm11 = r'C:\Gis\arcpy_teste\teste.shp'

rasters = arcpy.ListRasters()

def clipRaster(clipper, outws, raster):
     arcpy.Clip_management(raster, "#", os.path.join(outws, raster), clipper, 0, "ClippingGeometry")

def clipRasterMulti(processList):
    pool = Pool(processes=4, maxtasksperchild=10)
    jobs= {}
    for item in processList:
        jobs[item[0]] = pool.apply_async(clipRaster, [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():
    processList = [(clipper_utm11,outws_utm11, ras) for ras in rasters]
    clipRasterMulti(processList)
    print "Processing complete."

if __name__ == '__main__':
    main()