我在python中使用Multiprocessing.Pool,我不理解正在发生的事情。这是一个伪版本,展示了我的意思:
from multiprocessing import Pool
from time import sleep
def f1():
for i in range(5):
sleep(.1)
print("f1:",i)
print("f1 exiting")
return('f1f1f1f1f1f1f1')
def f2():
for i in range(10):
sleep(.1)
print("f2:",i)
print("f2 exiting")
return('f2f2f2ff2f2f2f2f2f')
pool = Pool(processes=2)
print('starting apply_async for p1, p2')
p1 = pool.apply_async(f1)
p2 = pool.apply_async(f2)
print('finished apply_async for p1, p2')
print('starting get() for p1, p2')
print(p1.get(timeout=10))
print(p2.get(timeout=10))
print('finished get() for p1, p2')
print('nnndone')
如果我运行这个,f1和f2同时运行和输出:
starting apply_async for p1, p2
finished apply_async for p1, p2
starting get() for p1, p2
f1: 0
f2: 0
f2: 1
f1: 1
f2: 2
f1: 2
f2: 3
f1: 3
f1: 4
f2: 4
f1 exiting
f1f1f1f1f1f1f1
f2: 5
f2: 6
f2: 7
f2: 8
f2: 9
f2 exiting
f2f2f2ff2f2f2f2f2f
finished get() for p1, p2
很明显,当p1调用get((时,它并没有阻止程序主要部分的其余部分的执行,而是立即转到p2.get((.
然而,如果我改为这样做(注意f1略有变化(:
from multiprocessing import Pool
from time import sleep
def f1():
for i in range(5):
sleep(1)
print("f1:",i)
print("f1 exiting")
return('f1f1f1f1f1f1f1')
def f2():
for i in range(10):
sleep(.1)
print("f2:",i)
print("f2 exiting")
return('f2f2f2ff2f2f2f2f2f')
pool = Pool(processes=1)
print('starting apply_async for p1')
p1 = pool.apply_async(f1)
print('finished apply_async for p1')
print('starting get() for p1')
print(p1.get(timeout=10))
print('finished get() for p1')
print('calling f2()')
f2()
print('nnndone')
我得到:
starting apply_async for p1
finished apply_async for p1
starting get() for p1
f1: 0
f1: 1
f1: 2
f1: 3
f1: 4
f1 exiting
f1f1f1f1f1f1f1
finished get() for p1
calling f2()
f2: 0
f2: 1
f2: 2
f2: 3
f2: 4
f2: 5
f2: 6
f2: 7
f2: 8
f2: 9
f2 exiting
因此,在这种情况下,p1.get((是程序的主要部分的阻塞。在这种情况下,如果我使用1或2个进程,也没有什么区别。
我知道这是因为在这种情况下,一个Pool工作人员没有调用f2,但我仍然感到困惑。更奇怪的是,如果我在第二种情况下切换f1和f2的顺序,比如:
pool = Pool(processes=1)
print('starting apply_async for p1')
p1 = pool.apply_async(f1)
print('finished apply_async for p1')
print('calling f2()')
f2()
print('starting get() for p1')
print(p1.get(timeout=10))
print('finished get() for p1')
当f2仍在执行时,它确实启动了f1的get((:
starting apply_async for p1
finished apply_async for p1
calling f2()
f2: 0
f2: 1
f2: 2
f2: 3
f2: 4
f2: 5
f2: 6
f2: 7
f2: 8
f1: 0
f2: 9
f2 exiting
starting get() for p1
f1: 1
f1: 2
f1: 3
f1: 4
f1 exiting
f1f1f1f1f1f1f1
finished get() for p1
(您可以在f2:8和f2:9之间看到f1:0。(
这真的让我很困惑。在这种情况下,f2与Pool的东西无关,那么当它第一次被调用时,它怎么不被阻塞呢?
有人能澄清一下Pool的情况吗?我看过文件,但它并没有真正为我澄清。
它在任何情况下都是阻塞的。第二个和第三个示例与第一个示例的不同之处在于,您没有打印出p1.get
和p2.get
之间的任何内容,因此无法从打印输出中看出它是否阻塞。一旦调用apply_async(f2)
,p2
就会开始运行,因此,当p1
仍在等待时,p2
会输出,但这与对p1.get
的调用无关。