Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 多处理时间随核数的增加而线性增加_Python_Multiprocessing_Arcpy - Fatal编程技术网

Python 多处理时间随核数的增加而线性增加

Python 多处理时间随核数的增加而线性增加,python,multiprocessing,arcpy,Python,Multiprocessing,Arcpy,我有一个arcpy过程,需要在一堆层上进行联合,运行一些计算,并编写一个HTML报告。考虑到我需要生成的报告数量(~2100),我需要这个过程尽可能快(我的目标是每个报告2秒)。我已经尝试了很多方法来实现这一点,包括当我遇到一个问题时的多处理,也就是说,无论我使用多少内核,运行多进程部分基本上都需要相同的时间 例如,对于相同数量的报告: 每轮2个核心需要约30秒(因此40份报告需要40/2*30秒) 4芯耗时约60秒(40/4*60) 10芯耗时约160秒(40/10*160) 等等。计算出

我有一个
arcpy
过程,需要在一堆层上进行联合,运行一些计算,并编写一个HTML报告。考虑到我需要生成的报告数量(~2100),我需要这个过程尽可能快(我的目标是每个报告2秒)。我已经尝试了很多方法来实现这一点,包括当我遇到一个问题时的多处理,也就是说,无论我使用多少内核,运行多进程部分基本上都需要相同的时间

例如,对于相同数量的报告:

  • 每轮2个核心需要约30秒(因此40份报告需要40/2*30秒)
  • 4芯耗时约60秒(40/4*60)
  • 10芯耗时约160秒(40/10*160)
等等。计算出来的总时间是相同的,因为一次翻腾两倍的数量需要两倍的时间

这是否意味着我的问题是I/O受限,而不是CPU受限?(如果是,我该怎么办?)我会认为是后者,因为我计时的最大瓶颈是并集(它占用了大约50%的处理时间)。在ArcGIS中,工会通常是昂贵的,所以我假设将其拆分并同时运行2-10会快2-10倍。或者,我可能会错误地实现多进程

## Worker function just included to give some context

def worker(sub_code):
    layer = 'in_memory/lyr_{}'.format(sub_code)
    arcpy.Select_analysis(subbasinFC, layer, where_clause="SUB_CD = '{}'".format(sub_code))
    arcpy.env.extent = layer
    union_name = 'in_memory/union_' + sub_code

    arcpy.Union_analysis([fields],
                     union_name,
                     "NO_FID", "1 FEET")
    #.......Some calculations using cursors

    # Templating using Jinjah
    context = {}
    context['DATE'] = now.strftime("%B %d, %Y")
    context['SUB_CD'] = sub_code
    context['SUB_ACRES'] = sum([r[0] for r in arcpy.da.SearchCursor(union, ["ACRES"], where_clause="SUB_CD = '{}'".format(sub_code))])
    # Etc

    # Then write the report out using custom function
    write_html('template.html', 'output_folder', context)


if __name__ == '__main__':
    subList = sorted({r[0] for r in arcpy.da.SearchCursor(subbasinFC, ["SUB_CD"])})
    NUM_CORES = 7
    chunk_list = [subList[i:i+NUM_CORES] for i in range(0, len(subList), NUM_CORES-1)]
    for chunk in chunk_list:
        jobs = []
        for subbasin in chunk:
            p = multiprocessing.Process(target=worker, args=(subbasin,))
            jobs.append(p)
            p.start()

        for process in jobs:
            process.join()

我不确定您是否正确使用
流程
池来跟踪您的作业。这:

for subbasin in chunk:
    p = multiprocessing.Process(target=worker, args=(subbasin,))
    jobs.append(p)
    p.start()

    for process in jobs:
        process.join()
应改为:

for subbasin in chunk:
    p = multiprocessing.Process(target=worker, args=(subbasin,))
    p.start()
    p.join()

你反对这项法案有什么具体原因吗?您不会等到线程终止后再启动另一个进程,这只会创建一大堆不由父调用进程处理的进程。

我不确定您是否正确使用
进程池来跟踪作业。这:

for subbasin in chunk:
    p = multiprocessing.Process(target=worker, args=(subbasin,))
    jobs.append(p)
    p.start()

    for process in jobs:
        process.join()
应改为:

for subbasin in chunk:
    p = multiprocessing.Process(target=worker, args=(subbasin,))
    p.start()
    p.join()

你反对这项法案有什么具体原因吗?您不会等到线程终止后再启动另一个进程,这只会创建一大堆不由父调用进程处理的进程。

这里没有太多内容,我也没有使用ArcGIS的经验。所以我可以注意到两个更高层次的东西。首先,“通常”的方法是将
NUM_CORES=7
下面的所有代码替换为:

pool = multiprocessing.Pool(NUM_CORES)
pool.map(worker, subList)
pool.close()
pool.join()
map()。按原样,启动7个进程,然后等待它们全部完成。在最慢的进程消失之前完成的所有进程都将消失,它们的核心将闲置等待下一个外循环迭代。
使7个进程在作业期间保持活动状态,并在每个进程完成其最后一项工作后为其提供一项新工作

其次,此部分以逻辑错误结束:

chunk_list = [subList[i:i+NUM_CORES] for i in range(0, len(subList), NUM_CORES-1)]
您想要
NUM\u CORES
而不是
NUM\u CORES-1
。就这样,在你身边的第一时间

subList[0:7]
然后

然后


等等<代码>子列表[6]
子列表[12]
(etc)分别提取两次。子列表重叠。

这里没有太多内容,我也没有使用ArcGIS的经验。所以我可以注意到两个更高层次的东西。首先,“通常”的方法是将
NUM_CORES=7
下面的所有代码替换为:

pool = multiprocessing.Pool(NUM_CORES)
pool.map(worker, subList)
pool.close()
pool.join()
map()。按原样,启动7个进程,然后等待它们全部完成。在最慢的进程消失之前完成的所有进程都将消失,它们的核心将闲置等待下一个外循环迭代。
使7个进程在作业期间保持活动状态,并在每个进程完成其最后一项工作后为其提供一项新工作

其次,此部分以逻辑错误结束:

chunk_list = [subList[i:i+NUM_CORES] for i in range(0, len(subList), NUM_CORES-1)]
您想要
NUM\u CORES
而不是
NUM\u CORES-1
。就这样,在你身边的第一时间

subList[0:7]
然后

然后


等等<代码>子列表[6]
子列表[12]
(etc)分别提取两次。子列表重叠。

您没有向我们展示足够的信息来确定您在做什么。例如,您的
环境工作区是什么?
subbasinFC
的值是多少?似乎您在每个流程的开始处都在进行分析,以将数据过滤到
。但是
subbasinFC
是来自磁盘还是内存?如果它来自磁盘,我建议您在任何进程尝试过滤之前将所有内容读入内存。如果你有足够的内存支持的话,这会加快事情的发展。否则,是的,输入数据将被I/O绑定


请原谅我的
arcpy
cluelessness,但是为什么要在
上下文['SUB_ACRES']
的总和中插入where子句呢?你不是一开始就已经过滤了
子代码
?(我们不知道工会是什么,所以可能你正在与未经过滤的东西建立工会…

你没有向我们展示足够的信息来确定你在做什么。例如,您的
环境工作区是什么?
subbasinFC
的值是多少?似乎您在每个流程的开始处都在进行分析,以将数据过滤到
。但是
subbasinFC
是来自磁盘还是内存?如果它来自磁盘,我建议您在任何进程尝试过滤之前将所有内容读入内存。如果你有足够的内存支持的话,这会加快事情的发展。否则,是的,输入数据将被I/O绑定

请原谅我的
arcpy
cluelessness,但是为什么要在
上下文['SUB_ACRES']
的总和中插入where子句呢?你不是一开始就已经过滤了
子代码
?(我们不知道联合是什么,所以可能您正在与未过滤的内容联合……

有多少个核心