在Python中使用ArcGIS进行多线程编程

4 投票
2 回答
3044 浏览
提问于 2025-04-16 11:12

我有一个Python脚本,单独运行的时候效果很好。这个脚本会根据一个固定的输入目录,扫描所有的.mdb文件,并把它们放到一个列表里,然后用一个循环逐个处理这些文件。每次处理都涉及多个表的限制、连接、查询等等。

唯一的问题是……在处理这个输入数据集时,它大约需要36个小时才能完成。虽然这个脚本只会在这个特定的数据集上使用,但我希望能提高它的运行效率,因为我经常需要修改字段选择、包含的结果、连接方法等等。我想说它运行得慢是因为我的脚本效率低,但实际上任何效率低下的地方都很小,因为几乎所有的处理时间都花在了地理处理器对象上。

在我的主脚本中,相关的部分是:

indir = "D:\\basil\\input"
mdblist = createDeepMdbList(indir)
for infile in mdblist:
    processMdb(infile)

这个脚本在顺序执行时也能完美运行。

我尝试过使用Parallel Python:

ppservers = ()
job_server = pp.Server(ppservers=ppservers)

inputs = tuple(mdblist)
functions = (preparePointLayer, prepareInterTable, jointInterToPoint,\
          prepareDataTable, exportElemTables, joinDatatoPoint, exportToShapefile)
modules = ("sys", "os", "arcgisscripting", "string", "time")

fn = pp.Template(job_server, processMdb, functions, modules)
jobs = [(input, fn.submit(input)) for input in inputs]

它成功创建了8个进程和8个地理处理器对象……然后就失败了。

我没有深入研究Python内置的多线程工具,但希望能得到一些指导,简单地启动最多8个进程来处理mdblist这个队列。在任何时候,都不会有多个进程同时尝试读取或写入文件。为了暂时简化事情,我还因为这个担忧去掉了所有的日志工具;我已经运行这个脚本足够多次,知道它能正常工作,除了4104个输入文件中的4个文件,它们的数据格式稍有不同。

有什么建议吗?在尝试多线程Arc Python脚本时有什么经验吗?

2 个回答

-1

我在同一个函数里对上面的方法进行了比较。结果是:

Starting pp with 1 workers
Time elapsed:  4.625 s

Starting pp with 2 workers
Time elapsed:  2.43700003624 s

Starting pp with 4 workers
Time elapsed:  2.42100000381 s

Starting pp with 8 workers
Time elapsed:  2.375 s

Starting pp with 16 workers
Time elapsed:  2.43799996376 s

Starting mul_pool with 1 p
Time elapsed:  5.31299996376 s

Starting mul_pool with 2
Time elapsed:  3.125 s

Starting mul_pool with 4
Time elapsed:  3.56200003624 s

Starting mul_pool with 8
Time elapsed:  4.5 s

Starting mul_pool with 16
Time elapsed:  5.92199993134 s
5

我想分享一下我找到的解决办法和我的一些经验。

根据Joe的评论,我使用了multiprocessing模块的回溯版本(code.google.com/p/python-multiprocessing),效果很好。我在我的脚本中做了一些调整,以处理本地和全局变量以及日志记录。

现在的主脚本是:

if __name__ == '__main__':

    indir = r'C:\basil\rs_Rock_and_Sediment\DVD_Data\testdir'
    mdblist = createDeepMdbList(indir)

    processes = 6  # set num procs to use here
    pool = multiprocessing.Pool(processes)

    pool.map(processMdb, mdblist)

总时间从大约36小时减少到了8小时,使用了6个进程。

我遇到的一些问题是,使用独立的进程时,它们会使用不同的内存空间,并且完全不使用全局变量。可以使用队列来解决这个问题,但我还没有实现,所以所有变量都是在本地声明的。

此外,由于pool.map只能接受一个参数,每次迭代都必须创建并删除geoprocessor对象,而不能一次性创建8个并在每次迭代中传递一个可用的对象。每次迭代大约需要一分钟,所以创建对象的几秒钟并不算什么,但时间加起来也不少。我还没有进行具体的测试,但这实际上可能是个好习惯,因为任何使用过Arcgis和Python的人都知道,脚本在geoprocessor活动时间越长,速度就会显著变慢(例如,我的一个脚本被同事使用时,输入过载,完成时间的估计从运行1小时后的50小时变成了过夜后350小时,再到运行2天后800小时……最后被取消并限制了输入)。

希望这能帮助到其他想要对大量可迭代输入进行多进程处理的人。下一步:递归的多进程追加!

撰写回答