我正在尝试使用并行计算编写一个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 Pool
时,您需要确保函数和参数可以序列化,因为它们将通过pipe
传输。
Python使用pickle
协议来序列化其对象。您可以在模块文档中查看可以腌制的内容。就您而言,您正在面临此限制。
在模块的最高级别定义的功能(使用def,而不是lambda)
在引擎盖下,Pool
正在发送带有函数名称及其参数的字符串。儿童过程中的python解释器在模块中寻找该函数名称,并且在嵌套在另一个函数 parallelSum
的范围中时未能找到它。
移动sumPartLocal
在parallelSum
外部,一切都可以。
我相信您正在击中它,或者查看文档
您可以做的是在模块级别离开def sumPartLocal
,然后将theArray
作为tuple
的第三个组件,因此在sumPartLocal
函数中是fromTo[2]
。
示例:
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)
[基于评论的编辑15-Dec-2017]
任何想在Python中考虑多线程的人,我强烈建议您阅读有关全球口译锁的信息
另外,在此问题上,关于