python - 为什么 python 的多处理池 get() 函数有时会阻塞而不是其他?
问题描述
我在 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('\n\n\ndone')
如果我运行它, 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('\n\n\ndone')
我得到:
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 个进程也没有什么区别。
我知道这是因为在这种情况下,f2 没有被其中一名 Pool 工作人员调用,但我仍然感到困惑。对我来说更奇怪的是,如果我在第二种情况下切换 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
and之间p2.get
的任何内容,因此无法从打印输出中查看它是否阻塞。p2
调用后立即开始运行apply_async(f2)
,因此为什么您从p2
whilep1
仍在等待中获得输出,但这与您调用p1.get
.
推荐阅读
- azure-powershell - 用于预配托管专用终结点的 Azure Synapse Analytics Powershell 或 CLI
- ios - 应用平移变换时,UICollectionViewFlowLayout 边缘单元格消失
- reactjs - 反应不是第一次没有更新
- matlab - GAN 在时间序列中生成奇数边
- bigcommerce - 在订单确认页面获取 OrderId
- linux - 在 Windows 主机上编译 WebRTC Linux ARM
- c# - 对于自定义操作,如何从 Blend 列表中选择一个属性?
- xml - XML 配置比较以检测任何新密钥并在现有配置中添加密钥
- jquery - 数据列中字符串格式的日期列的排序
- javascript - 列表中有多个jodit编辑器,但是当我更改编辑器特定索引状态的值时,它会重置最后一项除外。下面提供代码