python multiprocessing.Pipe的close()問題

(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()問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章