第三十七天 管道、信号、信号量

1.一段代码一段时间被一个人访问可以使用lock方法,如果一段代码同一时间被n个进程访问/或者说被n个进程执行用甚么指令?

  使用semaphore

  第一段代码:

from multiprocessing import  Process,Semaphore
import time
def ktv(i):
    print('%s走了进来'%i)
    time.sleep(2)
    print('%s走了出来'%i)
if __name__=='__main__':
    for i in range(20):
        s=Semaphore(4)
        p=Process(target=ktv,args=(i,))
        p.start()
结果为
3走了进来
8走了进来
0走了进来
4走了进来
6走了进来
11走了进来
10走了进来
7走了进来
5走了进来
1走了进来
12走了进来
18走了进来
15走了进来
16走了进来
2走了进来
14走了进来
9走了进来
17走了进来
13走了进来
19走了进来
3走了出来
8走了出来
0走了出来
4走了出来
6走了出来
11走了出来
10走了出来
7走了出来
5走了出来
1走了出来
12走了出来
18走了出来
15走了出来
16走了出来
2走了出来
14走了出来
9走了出来
17走了出来
13走了出来
19走了出来
View Code

从结果我们可以发现所有人都可以进入此ktv但时此ktv只有4个房间,很明显不合理:

  第二段代码:

from multiprocessing import  Process,Semaphore
import time
def ktv(i,s):
    s.acquire() #获取钥匙
    print('%s走了进来'%i)
    time.sleep(2)
    print('%s走了出来'%i)
    s.release()  #进行要是归还
if __name__=='__main__':
    s=Semaphore(4)   #创建类并进行允许数量的控制,及一个计数信号量
    for i in range(20):
        p=Process(target=ktv,args=(i,s))
        p.start()

结果为4走了进来
3走了进来
1走了进来
8走了进来
4走了出来
0走了进来
3走了出来
6走了进来
1走了出来
2走了进来
8走了出来
7走了进来
0走了出来
11走了进来
6走了出来
10走了进来
2走了出来
14走了进来
7走了出来
5走了进来
11走了出来
13走了进来
10走了出来
17走了进来
14走了出来
9走了进来
5走了出来
16走了进来
13走了出来
12走了进来
17走了出来
18走了进来
9走了出来
15走了进来
16走了出来
19走了进来
12走了出来
18走了出来
15走了出来
19走了出来
View Code

2.信号:

一个信号可以使所有的进程都进入堵塞状态,也可使所有控制的进程都接触堵塞状态,一个事件被创建之后,默认是堵塞状态

from multiprocessing import Event
a=Event()  #创建了一个事件的类
print(a.is_set()) #查看现在事件的状态#默认状态时False
a.wait()  
print('1900')#如果事件状态为False则指令不执行
结果为
False
View Code

  那么怎么才能让程序执行那:使用对象.set

from multiprocessing import Event
a=Event()  #创建了一个事件的类
print(a.is_set()) #查看现在事件的状态#默认状态时False
a.set()  #将事件状态转为True
a.wait()
print(a.is_set())
print('1900')#如果事件状态为True则指令执行
结果为
False
True
1900
View Code

  那么怎么才能把程序转为False

from multiprocessing import Event
a=Event()  #创建了一个事件的类
print(a.is_set()) #查看现在事件的状态#默认状态时False
a.set()  #将事件状态转为True
a.wait()
print(a.is_set())
print('1900')#如果事件状态为True则指令执行
a.clear()
print(a.is_set())
a.wait()#根据is_set的值来确定是否进行堵塞,没有这一步堵塞与否执行不起来
print('12345')
结果为
False
True
1900
False
View Code

总结:set和clear用来改变事件的运行状态,is_set()是用来判别事件现在的状态,wait根据is_set()的值来判断是否堵塞

 

3.红绿灯程序 

from multiprocessing  import Process
import time
def traffic_light():
    while True:
        print('\033[31m红等亮了\033[0m')
        time.sleep(3)
        print('\033[32m绿灯亮了\033[0m')
        time.sleep(3)
if __name__=='__main__':
        p=Process(target=traffic_light)
        p.start()
结果为
C:\pycharm\python.exe D:/python练习程序/第三十七天/practise.py
红等亮了
绿灯亮了
红等亮了
绿灯亮了
红等亮了
绿灯亮了
红等亮了
绿灯亮了
红等亮了
绿灯亮了
红等亮了
View Code

  如果再加一个车的程序,要求红灯车等待,绿灯车通行:

from multiprocessing  import Process,Event
import time
def car(a,i):
    if a.is_set():
        a.wait()
        print('%s车进程等待'%i)
    else:
        a.wait()
        print('%s车通过'%i)
def traffic_light(a):
    while True:
        if a.is_set():
            print('\033[31m红等亮了\033[0m')
            time.sleep(3)
            a.clear()
        else:
            print('\033[32m绿灯亮了\033[0m')
            time.sleep(3)
            a.set()
if __name__=='__main__':
        a=Event()
        p=Process(target=traffic_light,args=(a,))
        p.start()
        for i in range(20):
            p1=Process(target=car,args=(a,i))
            p1.start()
            time.sleep(1)
结果为
绿灯亮了
3车通过
0车通过
2车通过
1车通过
红等亮了
4车进程等待
5车进程等待
6车进程等待
绿灯亮了
9车通过
7车通过
8车通过
红等亮了
10车进程等待
11车进程等待
绿灯亮了
View Code

4.队列的程序·:

  正常情况下:

from multiprocessing import Queue
q=Queue(4)
q.put(1)
q.put(2)
q.put(3)
q.put(4)
结果为
C:\pycharm\python.exe D:/python练习程序/第三十七天/practise.py

Process finished with exit code 0
View Code

  放入的元素超过了自己设置的容器容量:程序会进入堵塞状态,如果程序中队列元素已经去玩,再去get则也会进入堵塞状态

from multiprocessing import Queue
q=Queue(4)#实例化一个队列对象,并设置容器大小
q.put(1)
q.put(2)
print(q.full())
q.put(3)
q.put(4)
print(q.full())#判断容器是否已经装满
结果为
False
True
View Code
from multiprocessing import Queue
q=Queue(4)#实例化一个队列对象,并设置容器大小
q.put(1)
q.put(2)
print(q.full())
q.put(3)
q.put(4)
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.empty())#用于判断队列中元素是否已经取完
结果为
False
1
2
3
4
View Code

5. q.get()方法:

返回q中的一个项目,如果q为空,此方法则进入堵塞状态,直到队列中项目可用为止。block用于控制阻塞行为,默认为True

6.q.put()

将item放入到队列中,如果队列已经满了,此方法将堵塞至空间可以用为止。

7.队列的作用主要适用于进程于进程之间进行数据通讯的:

  1.主进程和子进程之间的通讯:

from multiprocessing import Process,Queue
def func(q):
    q.put('hello')
if __name__=='__main__':
    q=Queue()
    p=Process(target=func,args=(q,))
    p.start()
    print(q.get())#通过队列可以进行子进行和主进程之间数据交流
结果为
hello
View Code

  2.子进程与子进程之间的通讯:

from multiprocessing import Process,Queue
def procuder(q):
    q.put('hello') #进行数据的存储
def user(q):
    print(q.get()) #进行数据的获取
if __name__=='__main__':
    q=Queue()
    p=Process(target=procuder,args=(q,))
    p.start()
    p1=Process(target=user,args=(q,))
    p1.start()
结果为
hello
View Code

 

8.包子机制

1.一般对数据处理会有两个过程:

 

 2.生产包子程序:

from multiprocessing import Process,Queue
import time
def procuder(name,food,q):
    for i in range(10):
        time.sleep(1)
        production='%s制造了第%s个%s'%(name,i,food)
        q.put(production)
        print(production)
if __name__=='__main__':
    q=Queue(30)
    p=Process(target=procuder,args=('alex','包子',q))
    p.start()
    p1=Process(target=procuder,args=(('xiaohong','面包',q)))
    p1.start()
结果为
C:\pycharm\python.exe D:/python练习程序/第三十七天/practise.py
alex制造了第0个包子
xiaohong制造了第0个面包
alex制造了第1个包子
xiaohong制造了第1个面包
xiaohong制造了第2个面包
alex制造了第2个包子
xiaohong制造了第3个面包
alex制造了第3个包子
xiaohong制造了第4个面包
alex制造了第4个包子
xiaohong制造了第5个面包
alex制造了第5个包子
alex制造了第6个包子
xiaohong制造了第6个面包
alex制造了第7个包子
xiaohong制造了第7个面包
alex制造了第8个包子
xiaohong制造了第8个面包
xiaohong制造了第9个面包
alex制造了第9个包子
View Code

3.吃包子过程:

from multiprocessing import Process,Queue
import time
import random
def procuder(name,food,q):
    for i in range(10):
        time.sleep(1)
        production='%s制造了第%s个%s'%(name,i,food)
        q.put(production)
        print(production)
def eat(name,q):
    while True:
        time.sleep(random.randint(1,4))
        msg=q.get()
        print('%s吃了%s'%(name,msg))
if __name__=='__main__':
    q=Queue(30)
    p=Process(target=procuder,args=('alex','包子',q))
    p.start()
    p1=Process(target=procuder,args=(('xiaohong','面包',q)))
    p1.start()
    p2=Process(target=eat,args=(('sir',q)))
    p2.start()
结果为
ir吃了alex制造了第0个包子
xiaohong制造了第5个面包
alex制造了第5个包子
xiaohong制造了第6个面包
alex制造了第6个包子
xiaohong制造了第7个面包
alex制造了第7个包子
sir吃了xiaohong制造了第1个面包
xiaohong制造了第8个面包
alex制造了第8个包子
xiaohong制造了第9个面包
alex制造了第9个包子
sir吃了alex制造了第1个包子
sir吃了xiaohong制造了第2个面包
sir吃了alex制造了第2个包子
sir吃了xiaohong制造了第3个面包
sir吃了alex制造了第3个包子
sir吃了xiaohong制造了第4个面包
sir吃了alex制造了第4个包子
sir吃了xiaohong制造了第5个面包
sir吃了alex制造了第5个包子
sir吃了xiaohong制造了第6个面包
sir吃了alex制造了第6个包子
sir吃了xiaohong制造了第7个面包
sir吃了alex制造了第7个包子
sir吃了xiaohong制造了第8个面包
sir吃了alex制造了第8个包子
sir吃了xiaohong制造了第9个面包
sir吃了alex制造了第9个包子
View Code

通过结果我们可以看出包子生产完成之后,sir一直在吃,没有办法进行终止,而且吃完所有包子以后进入堵塞状态,这种现象应该怎么解决:

  第一种方法使用q.empty进行判断但是发现解决还是没有办法进行终止:

from multiprocessing import Process,Queue
import time
import random
def procuder(name,food,q):
    for i in range(10):
        time.sleep(1)
        production='%s制造了第%s个%s'%(name,i,food)
        q.put(production)
        print(production)
        if q.empty==True:
            break
def eat(name,q):
    while True:
        time.sleep(random.randint(1,2))
        msg=q.get()
        print('%s吃了%s'%(name,msg))
if __name__=='__main__':
    q=Queue(30)
    p=Process(target=procuder,args=('alex','包子',q))
    p.start()
    p1=Process(target=procuder,args=(('xiaohong','面包',q)))
    p1.start()
    p2=Process(target=eat,args=(('sir',q)))
    p2.start()
    p3=Process(target=eat,args=(('lao',q)))
    p3.start()
View Code

 

   第二种方法:使用joinableQueue

from multiprocessing import Process,JoinableQueue
import time
import random
def procuder(name,food,q):
    for i in range(10):
        time.sleep(1)
        production='%s制造了第%s个%s'%(name,i,food)
        q.put(production)
        print(production)
    q.join()#感知一个队列的数据,全部被执行完毕结束
def eat(name,q):
    while True:
        time.sleep(random.randint(1,2))
        msg=q.get()
        print('%s吃了%s'%(name,msg))
        q.task_done() #没执行玩一次进行计数减一
if __name__=='__main__':
    q=JoinableQueue(30)
    p=Process(target=procuder,args=('alex','包子',q))
    p.start()
    p1=Process(target=procuder,args=(('xiaohong','面包',q)))
    p1.start()
    p2=Process(target=eat,args=(('sir',q)))
    p2.daemon=True#设置此进程为守护进程,当主程序结束时,子进程结束
    p2.start()
    p3=Process(target=eat,args=(('lao',q)))
    p3.daemon=True
    p3.start()
    p.join() #感知一个子进程的结束
    p1.join()
View Code

结果为

 

 执行过程如下:

在生产者这一端:
    每一次生产一个数据,
    且每一次生产的数据都要放在队列中
    在队列中刻上一个记号
    当生产者全部生产完毕以后
    join信号,已经停止生产数据,开始等待数据的使用完毕处理结束完之前都属于堵塞状态
之后数据处理结束后join'堵塞状态结束
消费者这一端的程序:
consumer中把所有的任务都消耗完成
皮绒促的人端的join感知到,停止堵塞
所有的prodecuer进程结束
主进程代码结束
守护进程也结束
View Code

 


 

posted @ 2020-03-13 17:06  chown  阅读(99)  评论(0编辑  收藏  举报