(conn1, conn2) = Pipe([duplex])
conn1,conn2表示管道兩端的connection對象
默認情況下,管道是雙向的
如duplex設置爲False,conn1只能用於接收,conn2只能用於發送
必須在創建和啓動使用管道的Process對象之前調用Pipe()方法
python進程間通信
應該特別注意管道端點的正確管理問題。
1.如果是生產者或消費者中都沒有使用管道的某個端點,就應將它關閉。
2.這也說明了爲何在生產者中關閉了管道的輸出端,在消費者中關閉管道的輸入端。
3.如果忘記執行這些步驟,程序可能在消費者中的recv()操作上掛起。
4.管道是由操作系統進行引用計數的,必須在所有進程中關閉管道後才能生成EOFError異常。
5.因此,在生產者中關閉管道不會有任何效果,除非消費者也關閉了相同的管道端點。
主要講close問題,和recv卡住問題
recv卡住是因爲他要等待管道中有數據接收,如果沒數據就卡住,但是我想觸發EOFError,看有人解釋是當管道中數據沒有東西時就會拋出EOFError,但是我這裏死活不拋出,就是卡住。
後來發現是close的問題!!
假設有一個管道 分爲A,B端,A端send數據,B端recv數據(其實是雙工,只是這樣不亂)
最後想明白了,B端recv報錯是在確定了管道的另一端不會有數據傳來後才報錯,否則就一直阻塞,直到有數據從管道另一端傳來。一個進程的A端close了只是這個進程的A端不能send數據了,但是別的進程如果有A端,別的進程就能發送數據,只有當所有進程中的A端都關閉了才能算真正的close了。
進程1調用了close,但是進程2仍然能send,進程3也能send,所以管道左邊還是能有數據進入,
上邊錯誤代碼中,父進程中創建了一個a,b=Pipe(),這裏a雖然傳入進程中了,但是相當於在父進程裏還有一個a端,所以要想代碼成功運行,那麼就要在父進程中使用a.close()才行,但是要注意不能再start()函數前close()不然會報OSError: handle is closed
如下:
from multiprocessing import Process
from multiprocessing import Pipe
import os
import time
def send(a):
print("這是send子進程的id", os.getpid())
a.send("hello")
a.close() #此處close()一次,內部的close
def recv(b):
print("這是recv子進程的id", os.getpid())
try:
print(b.recv())
print(b.recv())
except EOFError:
print("end")
if __name__ == "__main__":
print("父進程的pid", os.getpid())
a, b = Pipe(True)
p_send = Process(target=send, args=(a,))
p_send.start()
p_recv = Process(target=recv, args=(b,))
p_recv.start()
a.close() #內部的close了,外部的也要close
p_send.join()
p_recv.join()
print("結束了")
以下實例比較能說明疑惑:
- 在consumer中,conn2.close()了,在單獨進程cons_p中執行,但producer中conn2還能發送數據?
- 在main中,conn1.close()了,在但是在單獨進程cons_p的consumer中,conn1還能接收數據?
這表示main中和Process中的兩個conn1,conn2有關聯,但是又不同,需單獨執行close()方法。
可是在使用id去檢查的時候,發現id都是一樣的,其中的關聯和不同之處比較費解!
import multiprocessing
import os
def consumer(pipe):
conn1, conn2 = pipe
print 'consumer conn1 id',id(conn1)
print 'consumer conn2 id',id(conn2)
print("process consumer id", os.getpid())
conn2.close() # input pipe close 1
while True:
try:
item = conn1.recv()
except EOFError:
print 'EOFError'
break
print item
print 'consumer done'
def producer(listArr, conn2):
for item in listArr:
conn2.send(item)
if __name__ == '__main__':
(conn1, conn2) = multiprocessing.Pipe()
cons_p = multiprocessing.Process(target=consumer, args=((conn1,conn2),))
cons_p.start()
conn1.close() # output pipe clsoe 1
arr = [1,2,3,4,5]
producer(arr, conn2)
print ' main conn1 id',id(conn1)
print ' main conn2 id',id(conn2)
conn2.close() # input pipe close 2
cons_p.join()
執行結果爲:
main conn1 id 140624342823424
main conn2 id 140624342872576
consumer conn1 id 140624342823424
consumer conn2 id 140624342872576
('process consumer id', 57429)
1
2
3
4
5
EOFError
consumer done
參考:
Python進程間通信
Python multiprocessing Process和Pipe管理問題
Pipe recv()和close()問題