进程间的通信

★管道
Python中的管道有两种工作方式:
1,单项(半双工)
一端只能发送数据,另一端只能接收数据。
2,双向(全双工)
两端都既能发送数据又能接收数据,一端发送的数据只能由另一端接收。

标准库模块multiprocessing中提供了一个函数Pipe(),其返回值是一个元组,元组中包含两个对象,
分别表示管道两端的连接。
调用函数Pipe()时,如果不传入参数或传入参数为True,管道的工作方式为双向(全双工);
如果传入的参数为False,管道的工作方式为单向(半双工),其中,对于返回的元组,第一个
连接对象只能接收数据,第二个连接对象只能发送数据。

对于管道两端的连接对象,主要由两个方法:
1,send(self,obj)
用于将参数obj指定的对象发送到管道。
2,recv(self)
用于从管道中接收对象。

 1 from multiprocessing import Pipe
 2 
 3 #conn1和conn2为管道的两端。
 4 conn1, conn2 = Pipe() #Pipe()或Pipe(True)为全双工
 5 
 6 conn1.send('conn1第1次发送的数据')
 7 conn1.send('conn1第2次发送的数据')
 8 
 9 conn2.send('conn2第1次发送的数据')
10 conn2.send('conn2第2次发送的数据')
11 
12 print(conn1.recv()) 
13 print(conn1.recv()) 
14 
15 print(conn2.recv()) 
16 print(conn2.recv()) 
17 
18 
19 #测试半双工
20 c1, c2 = Pipe(False)  #Pipe(False)为半双工。c1只能接收,c2只能发送。
21 
22 c2.send('c2发送的数据')
23 print(c1.recv())    
24 
25 # c1.send('c1发送的数据') #OSError: connection is read-only
View Code

#【1】进程间的通信之管道

管道是实现进程间通信的常见方式之一。

 1 from multiprocessing import Process, Pipe
 2 import os, time, random
 3 
 4 #发送数据的子进程执行
 5 def send_data(conn):
 6     print('发送数据的子进程%d启动' % os.getpid())
 7 
 8     for obj in list(range(1, 10)):
 9         print('发送数据:%s' % obj)
10         conn.send(obj)
11         time.sleep(random.random() * 3)
12 
13     print('发送数据:None')
14     conn.send(None)
15 
16     print('发送数据的子进程%d结束' % os.getpid())
17     
18 #接收数据的子进程执行
19 def recv_data(conn):
20     print('接收数据的子进程%d启动' % os.getpid())
21 
22     while True:
23         item = conn.recv()
24         if item is None:
25             print('接收数据:None')
26             break
27         print('接收数据:%s' % item)
28         time.sleep(random.random() * 3)
29 
30     print('接收数据的子进程%d结束' % os.getpid())
31 
32 print('父进程%d启动' % os.getpid())
33 
34 cr, cs = Pipe(False) #半双工
35 
36 ps = Process(target=send_data, args=(cs,))  #args指定target接收的参数。
37 pr = Process(target=recv_data, args=(cr,))
38 
39 ps.start()
40 pr.start()
41 
42 #两个子进程阻塞父进程
43 ps.join()
44 pr.join()
45 
46 print('父进程%d结束' % os.getpid())
View Code
 1 from multiprocessing import Process, Pipe
 2 
 3 def f(conn):
 4     conn.send([1, {"name":"Li"}, 'hi'])
 5     response=conn.recv()
 6     print("response",response)
 7     conn.close()
 8     print("c_conn传入子进程后的id:",id(conn))
 9 
10 if __name__ == '__main__':
11 
12     p_conn, c_conn = Pipe() #全双工
13     print("c_conn在主进程中的id:",id(c_conn))
14     p = Process(target=f, args=(c_conn,))
15     p.start()
16     print(p_conn.recv())   
17     p_conn.send("hello!")
18     p.join()
View Code

#【2】进程间的通信之Manager

如果想要实现进程间的通信,Manager也是常见的实现方式之一。
与共享内存相比,Manager更加灵活,因为它可以支持多种对象类型。此外,Manager还可以通过网络
被不同的计算机上的进程所共享。但是,Manager的速度比共享内存慢。

 1 from multiprocessing import Process, Manager
 2 
 3 #子进程执行操作
 4 def f(d,l):
 5     d[1] = 18
 6     d['2'] = 56
 7     l.reverse()  #列表反转
 8 if __name__ == '__main__':
 9     manager = Manager()
10 
11     #通过Manager创建一个用于进程间通信的字典
12     d = manager.dict()
13     #通过Manager创建一个用于进程间通信的列表
14     l = manager.list(range(5))
15 
16     p = Process(target=f,args=(d,l,))
17     p.start()
18     p.join()  #阻塞父进程
19 
20     print(d)
21     print(l)
View Code

 #【3】进程间的通信之共享内存

参考:另一篇博客

 #【4】进程间的通信之进程队列(multiprocessing.Queue())

 1 #import queue
 2 #import time
 3 import multiprocessing
 4 q = multiprocessing.Queue()
 5 
 6 
 7 def foo(q, n):
 8     q.put(1)
 9     q.put(2)
10     print("子进程:", id(q))
11 
12 
13 if __name__ == '__main__':
14     #q=queue.Queue() #<--错误;这个为线程队列,不能在进程间共享队列元素。
15     procList = []
16     print("主进程:", id(q))
17     for i in range(2):
18         p = multiprocessing.Process(target=foo, args=(q, i))#此处用进程队列。
19         p.start()
20         procList.append(p)
21     #q.start()
22     for p in procList:#阻塞主進程
23         p.join()
24     #time.sleep(5)
25     print(q.get())
26     print(q.get())
View Code

 

posted @ 2019-06-30 23:29  山的那一边  阅读(127)  评论(0)    收藏  举报