我在Python 3中使用多处理池遇到了一个非常奇怪的问题...请参阅下面的代码:
import multiprocessing as MP
class c(object):
def __init__(self):
self.foo = ""
def a(self, b):
return b
def main(self):
with open("/path/to/2million/lines/file", "r") as f:
self.foo = f.readlines()
o = c()
o.main()
p = MP.Pool(5)
for r in p.imap(o.a, range(1,10)):
print(r)
如果按原样执行此代码,这是我非常缓慢的结果:
1
2
3
4
5
6
7
8
9
real 0m6.641s
user 0m7.256s
sys 0m1.824s
但是,如果我删除了行o.main()
,那么我的执行时间会快得多:
1
2
3
4
5
6
7
8
9
real 0m0.155s
user 0m0.048s
sys 0m0.004s
我的环境有足够的力量,我已经确定我没有遇到任何内存限制。我还用较小的文件测试它,并且执行时间更容易接受。有什么见解吗?
编辑:我删除了磁盘IO部分,而只是创建了一个列表。我可以证明磁盘IO与问题无关......
for i in range(1,500000):
self.foo.append("foobar%d\n"%i)
real 0m1.763s user 0m1.944s sys 0m0.452s
for i in range(1,1000000):
self.foo.append("foobar%d\n"%i)
real 0m3.808s user 0m4.064s sys 0m1.016s
答案 0 :(得分:2)
在幕后,multiprocessing.Pool
使用Pipe
将数据从父进程传输到池工作人员。
当整个o
对象被序列化为Pickle
对象并通过OS管道传输时,这会增加任务调度的隐藏成本。
这是针对您正在安排的每个任务完成的(在您的示例中为10次)。如果您的文件大小为10 Mb,则表示您正在移动100 MB的数据。
根据multiprocessing Programming Guidelines:
应尽可能避免在流程之间转移大量数据。
加速逻辑的一种简单方法是计算文件中的行数,将它们分成相等的块,只将行索引发送给工作进程并让它们open
文件,{{ 1}}右边的行并处理数据。