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()问题

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