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