管道(from multiprocessing import Process,Pipe):
管道的介绍:
1 #创建管道的类:
2 Pipe([duplex]):在进程之间创建一条管道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process对象之前产生管道
3 #参数介绍:
4 dumplex:默认管道是全双工的,如果将duplex射成False,conn1只能用于接收,conn2只能用于发送。
5 #主要方法:
6 conn1.recv():接收conn2.send(obj)发送的对象。如果没有消息可接收,recv方法会一直阻塞。如果连接的另外一端已经关闭,那么recv方法会抛出EOFError。
7 conn1.send(obj):通过连接发送对象。obj是与序列化兼容的任意对象
8 #其他方法:
9 conn1.close():关闭连接。如果conn1被垃圾回收,将自动调用此方法
10 conn1.fileno():返回连接使用的整数文件描述符
11 conn1.poll([timeout]):如果连接上的数据可用,返回True。timeout指定等待的最长时限。如果省略此参数,方法将立即返回结果。如果将timeout射成None,操作将无限期地等待数据到达。
12
13 conn1.recv_bytes([maxlength]):接收c.send_bytes()方法发送的一条完整的字节消息。maxlength指定要接收的最大字节数。如果进入的消息,超过了这个最大值,将引发IOError异常,并且在连接上无法进行进一步读取。如果连接的另外一端已经关闭,再也不存在任何数据,将引发EOFError异常。
14 conn.send_bytes(buffer [, offset [, size]]):通过连接发送字节数据缓冲区,buffer是支持缓冲区接口的任意对象,offset是缓冲区中的字节偏移量,而size是要发送字节数。结果数据以单条消息的形式发出,然后调用c.recv_bytes()函数进行接收
15
16 conn1.recv_bytes_into(buffer [, offset]):接收一条完整的字节消息,并把它保存在buffer对象中,该对象支持可写入的缓冲区接口(即bytearray对象或类似的对象)。offset指定缓冲区中放置消息处的字节位移。返回值是收到的字节数。如果消息长度大于可用的缓冲区空间,将引发BufferTooShort异常。
方法总结:
Conn1,conn2 = Pipe() #创建一个管道对象,全双工,返回管道的两端,但是一端发送的消息,只能另外一端接收,自己这一端是不能接收的
Conn1.recv() #接收
Conn1.send() #发送
数据接收一次就没有了
图例:
关于管道会造成数据不安全问题的官方解释: The two connection objects returned by Pipe() represent the two ends of the pipe. Each connection object has send() and recv() methods (among others). Note that data in a pipe may become corrupted if two processes (or threads) try to read from or write to the same end of the pipe at the same time. Of course there is no risk of corruption from processes using different ends of the pipe at the same time.
由Pipe方法返回的两个连接对象表示管道的两端。每个连接对象都有send和recv方法(除其他之外)。注意,如果两个进程(或线程)试图同时从管道的同一端读取或写入数据,那么管道中的数据可能会损坏。当然,在使用管道的不同端部的过程中不存在损坏风险。
多个消费者竞争会出现数据不安全的问题的解决方案:加锁
1 from multiprocessing import Process,Pipe,Lock
2
3 def consumer(p,name,lock):
4 produce, consume=p
5 produce.close()
6 while True:
7 lock.acquire()
8 baozi=consume.recv()
9 lock.release()
10 if baozi:
11 print('%s 收到包子:%s' %(name,baozi))
12 else:
13 consume.close()
14 break
15
16
17 def producer(p,n):
18 produce, consume=p
19 consume.close()
20 for i in range(n):
21 produce.send(i)
22 produce.send(None)
23 produce.send(None)
24 produce.close()
25
26 if __name__ == '__main__':
27 produce,consume=Pipe()
28 lock = Lock()
29 c1=Process(target=consumer,args=((produce,consume),'c1',lock))
30 c2=Process(target=consumer,args=((produce,consume),'c2',lock))
31 p1=Process(target=producer,args=((produce,consume),10))
32 c1.start()
33 c2.start()
34 p1.start()
35
36 produce.close()
37 consume.close()
38
39 c1.join()
40 c2.join()
41 p1.join()
42 print('主进程')
事件(from multiprocessing import Process,Event):
E = Event() #初识状态是false
E.wait() 当事件对象e的状态为false的时候,在wait的地方会阻塞程序,当对象状态为true的时候,直接在这个wait地方继续往下执行
E.set() 将事件对象的状态改为true,
E.is_set() 查看状态
E.clear() 将事件对象的状态改为false
时间方法的使用:
1 from multiprocessing import Process,Semaphore,Event
2 import time,random
3
4 e = Event() #创建一个事件对象
5 print(e.is_set()) #is_set()查看一个事件的状态,默认为False,可通过set方法改为True
6 print('look here!')
7 # e.set() #将is_set()的状态改为True。
8 # print(e.is_set())#is_set()查看一个事件的状态,默认为False,可通过set方法改为Tr
9 # e.clear() #将is_set()的状态改为False
10 # print(e.is_set())#is_set()查看一个事件的状态,默认为False,可通过set方法改为Tr
11 e.wait() #根据is_set()的状态结果来决定是否在这阻塞住,is_set()=False那么就阻塞,is_set()=True就不阻塞
12 print('give me!!')
13
14 #set和clear 修改事件的状态 set-->True clear-->False
15 #is_set 用来查看一个事件的状态
16 #wait 依据事件的状态来决定是否阻塞 False-->阻塞 True-->不阻塞
通过事件来模拟红绿灯:
1 from multiprocessing import Process, Event
2 import time, random
3
4 def car(e, n):
5 while True:
6 if not e.is_set(): # 进程刚开启,is_set()的值是Flase,模拟信号灯为红色
7 print('