【问题标题】:How to write a function that sums a list using parallel computing?如何编写一个使用并行计算对列表求和的函数?
【发布时间】:2017-12-15 19:56:31
【问题描述】:

我正在尝试编写一个 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'

这个函数的正确写法是什么?

【问题讨论】:

标签: python-3.x multiprocessing


【解决方案1】:

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

Python 使用pickle 协议来序列化其对象。您可以在module documentation 中查看可以腌制的内容。就您而言,您正面临此限制。

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

在后台,Pool 正在发送一个带有函数名称及其参数的字符串。子进程中的 Python 解释器在模块中查找该函数名,但未能找到它,因为它嵌套在另一个函数 parallelSum 的范围内。

sumPartLocal 移到parallelSum 之外,一切都会好起来的。

【讨论】:

    【解决方案2】:

    我相信您正在点击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)
    

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

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

    另外,关于这个question here on SO的一些很好的答案

    【讨论】:

    • 这会返回正确的结果。但是,它需要的时间是全局变量版本的两倍,几乎是串行版本的时间。对于实验,我不只是求和,而是求和([x**3 for x in array])。我拿了数组= 50000000 * [1]。在我的电脑上,串行版本大约需要10.8,带全局数组的并行版本需要6.0秒,带函数的并行版本需要8.7秒...
    • 我想我知道为什么我的程序很慢 - 它正在序列化和反序列化整个巨大的数组。我做了一个实验,而不是一个数组,我计算一个函数的总和:sum([math.sin(x)**3 for x in range(0,20000000)])。在这里,多处理版本确实占用了串行版本的一半左右。
    猜你喜欢
    • 1970-01-01
    • 2021-09-08
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-21
    相关资源
    最近更新 更多