在Python中使用ArcGIS进行多线程编程
我有一个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 个回答
我在同一个函数里对上面的方法进行了比较。结果是:
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
我想分享一下我找到的解决办法和我的一些经验。
根据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小时……最后被取消并限制了输入)。
希望这能帮助到其他想要对大量可迭代输入进行多进程处理的人。下一步:递归的多进程追加!