[英]Why are Python multiprocessing Pipe unsafe?
我不明白為什么當有多個發送者和接收者時, Pipes
被認為是不安全的。
如果是這種情況,如何使用Queues
將以下代碼轉換為代碼? 關閉時Queues
不會拋出EOFError
,因此我的進程無法停止。 我是否應該無休止地發送“Poison”消息告訴他們停止(這樣,我確定我的所有進程都至少收到一個毒葯)?
我想保持管道p1
打開,直到我另有決定(這是我發送10條消息的時候)。
from multiprocessing import Pipe, Process
from random import randint, random
from time import sleep
def job(name, p_in, p_out):
print(name + ' starting')
nb_msg = 0
try:
while True:
x = p_in.recv()
print(name + ' receives ' + x)
nb_msg = nb_msg + 1
p_out.send(x)
sleep(random())
except EOFError:
pass
print(name + ' ending ... ' + str(nb_msg) + ' message(s)')
if __name__ == '__main__':
p1_in, p1_out = Pipe()
p2_in, p2_out = Pipe()
proc = []
for i in range(3):
p = Process(target=job, args=(str(i), p1_out, p2_in))
p.start()
proc.append(p)
for x in range(10):
p1_in.send(chr(97+x))
p1_in.close()
for p in proc:
p.join()
p1_out.close()
p2_in.close()
try:
while True:
print(p2_out.recv())
except EOFError:
pass
p2_out.close()
本質上,問題是Pipe
是一個圍繞平台定義的管道對象的薄包裝器。 recv
只是重復接收一個字節緩沖區,直到獲得完整的Python對象。 如果兩個線程或進程在同一個管道上使用recv
,則讀取可能會交錯,從而使每個進程都有半個pickle對象,從而破壞數據。 Queue
在進程之間進行適當的同步,但代價是更復雜。
正如multiprocessing
文檔所說:
請注意,如果兩個進程(或線程)同時嘗試讀取或寫入管道的同一端,則管道中的數據可能會損壞。 當然,同時使用管道的不同端的進程不存在損壞的風險。
你不必無休止地送毒葯; 每個工人一個就是你所需要的。 每個工人在退出之前都會拿出一個毒丸,所以工人不會錯過這個消息。
您還應該考慮使用multiprocessing.Pool
而不是重新實現“工作進程”模型 - Pool
有很多方法可以很容易地跨多個線程分配工作。
我不明白為什么當有多個發送者和接收者時,管道被認為是不安全的。
考慮您同時將水從源A和B放入管道中。 在管道的另一端,你不可能找出哪一部分水來自A或B,對嗎? :)
管道在字節級別上傳輸數據流。 如果沒有通信協議,它就不知道消息是什么,因此無法確保消息的完整性。 因此,使用具有多個發件人的管道不僅“不安全”。 這是一個重大的設計缺陷,很可能會導致溝通問題。
但是,隊列是在更高級別上實現的。 它們用於傳遞消息 (甚至是抽象對象)。 隊列用於保持消息/對象自包含。 多個源可以將對象放入隊列中,並且多個消費者可以拉動這些對象,同時100%確定作為一個單元進入隊列的任何內容也作為一個單元出現。
編輯了很長一段時間后:
我應該在字節流中添加,所有字節的檢索順序與發送(保證)相同。 多個發件人的問題是發送順序(輸入順序)可能已經不清楚或隨機,即多個流可能以不可預測的方式混合。
通用隊列實現可確保單個消息保持不變,即使有多個發件人也是如此。 消息也按發送的順序檢索。 但是,對於多個競爭發送器而沒有進一步的同步機制,再次無法保證輸入消息的順序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.