python多进程编程中导致程序在退出时卡住的两种情况
使用管道时
1 |
|
原理:创建管道,调用conn1
和conn2
的recv()
或recv_bytes()
方法时,如果对端已关闭且不存在数据项则会引发EOFError
异常。所以,多进程环境中如果生产者/消费者没有/不再使用管道的某个端点就应该将其关闭,以防止程序在管道的recv()
/recv_bytes()
方法上挂起。
管道是由操作系统进行引用计数的, 必须在所有进程中关闭管道才能生成
EOFError
异常!
问题复现
以下简单的代码展示了在不使用哨兵的情况下,程序在退出时卡住的现象:
1 |
|
运行结果如下,程序在退出时卡住(不论进程proc
的deamon
属性是否为False
):
规避方法
- 使用哨兵,有几个消费者,就传入几个哨兵:
c1.send(None)
, 推荐。 - 在进程中关闭不使用的管道,使进程产生
EOFError
异常,但需要额外的异常处理代码:
修改后的脚本如下:运行结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27import multiprocessing
def consumer(conn):
print(globals())
global c1
c1.close()
print("consumer start")
while True:
try:
obj = conn.recv()
except EOFError as e:
print(f"{e!r}")
break
if obj is None:
break
print(f"obj: {obj!r} recived.")
print("consumer done")
c1, c2 = multiprocessing.Pipe()
proc = multiprocessing.Process(target=consumer, args=(c2,))
proc.deamon = False
proc.start()
c1.send(123)
c1.close()
使用队列时
queue = multiprocessing.Queue()
原理:创建队列, 当队列使用完毕执行queue.close()
关闭时,队列关闭不会在消费者中的get()
方法上生成任何类型的信号或异常!
问题复现
以下简单的代码展示了在不使用哨兵的情况下,程序在退出时卡住的现象:
1 |
|
运行结果和使用管道时一样,程序在退出时卡住(不论进程proc
的deamon
属性是否为False
):
规避方法
使用哨兵,有几个消费者,就传入几个哨兵:queue.put(None)
python多进程编程中导致程序在退出时卡住的两种情况
https://www.tao-wt.fun/python/python-queue-pipe/