代码之家  ›  专栏  ›  技术社区  ›  Erel Segal-Halevi

如何编写使用并行计算对列表求和的函数?

  •  0
  • Erel Segal-Halevi  · 技术社区  · 7 年前

    我正在尝试编写一个Python函数,使用并行计算快速计算列表的和。最初我尝试使用Python多线程库,但后来我注意到所有线程都在同一个CPU上运行,因此没有速度提升,所以我转而使用多处理。在第一个版本中,我将列表作为一个全局变量:

    from multiprocessing import Pool
    
    array = 100000000*[1]
    
    def sumPart(fromTo:tuple):
        return sum(array[fromTo[0]:fromTo[1]])
    
    with Pool(2) as pool:
        print(sum(pool.map(sumPart, [(0,len(array)//2), (len(array)//2,len(array))])))
    

    这很好,在大约一半的串行计算时间后返回了正确的总和。

    但我想让它成为一个接受数组作为参数的函数:

    def parallelSum(theArray):
        def sumPartLocal(fromTo: tuple):
            return sum(theArray[fromTo[0]:fromTo[1]])
        with Pool(2) as pool:
            return (sum(pool.map(sumPartLocal, [(0, len(theArray) // 2), (len(theArray) // 2, len(theArray))])))
    

    这里有一个错误:

    AttributeError: Can't pickle local object 'parallelSum.<locals>.sumPartLocal'
    

    编写此函数的正确方法是什么?

    2 回复  |  直到 7 年前
        1
  •  2
  •   noxdafox    7 年前

    将作业调度到Python时 Pool 您需要确保函数及其参数都可以序列化,因为它们将通过 pipe .

    Python使用 pickle 序列化其对象的协议。你可以看到在 module documentation . 在您的情况下,您面临着这个限制。

    在模块顶层定义的函数(使用def,而不是lambda)

    在引擎盖下 水塘 正在发送包含函数名及其参数的字符串。子进程中的Python解释器在模块中查找该函数名,但由于它嵌套在另一个函数的作用域中,因此找不到该函数名 parallelSum .

    移动 sumPartLocal 外部 平行和 一切都会好起来的。

        2
  •  1
  •   Edwin van Mierlo    7 年前

    我相信你在打 this ,或查看 documentation

    你能做的就是离开 def sumPartLocal 在模块级,通过 theArray 作为您的 tuple 那就是 fromTo[2] 内部 sumPartLocal 作用

    例子:

    from multiprocessing import Pool
    
    def sumPartLocal(fromTo: tuple):
        return sum(fromTo[2][fromTo[0]:fromTo[1]]) 
    
    def parallelSum(theArray):
        with Pool(2) as pool:
            return (sum
                    (pool.map
                     (sumPartLocal, [
                         (0, len(theArray) // 2, theArray), 
                         (len(theArray) // 2, len(theArray), theArray)
                         ]
                      )
                     )
                    )
    
    if __name__ == '__main__':
        theArray = 100000000*[1]
        s = parallelSum(theArray)
        print(s)
    

    [根据评论编辑2017年12月15日]

    任何想在python中使用多线程的人,我强烈建议阅读 Global Interpreter Lock

    还有,关于这个问题的一些好答案 question here on SO