一、回顾
1、一些名词回顾:
并行:两个进程在同一时间点发生
并发:两个进程在同一时间间隔内运行
同步:某一个任务的执行必须依赖于另一个任务的返回结果
异步:某一个任务的执行,不需要依赖于另一个任务的返回,只需要告诉另一个任务一声
阻塞:程序因为类似IO等待,等待事件导致无法继续执行
非阻塞:程序遇到类似IO操作时,不再阻塞等待,如果没有及时的处理IO,就报错或者跳过等替他操作
2、进程的方法和属性:
(1)方法:
start( ) 开启一个进程
join( ) 异步变同步,让父进程等待子进程的结束,再继续执行
is_alive( ) 判断进程是否活着
terminate 杀死进程
(2)属性:
name 子进程的名称
pid 子进程的pid
daemon 设置进程为守护进程,给一个True代表为守护进程,默认为False
3、守护进程:
(1)特点:
随着父进程的结束而结束
守护进程不能创建子进程
守护进程必须要在start之前设置
(2)代码:
1 from multiprocessing import Process 2 3 import time 4 5 def func1(): 6 for i in range(65,90): 7 print(chr(i)) 8 time.sleep(0.5) 9 10 def func(): 11 for i in range(10): 12 print(i) 13 time.sleep(0.5) 14 15 if __name__ == '__main__': 16 p = Process(target=func) 17 p.start() 18 p1 = Process(target=func1) 19 p1.daemon = True 20 p1.start() 21 # time.sleep(2) 22 23 # print(p.is_alive()) 24 # p.terminate() 25 # p.join() 26 # print(p.is_alive()) 27 # print(p.pid,p.name) 28 # for i in range(10,21): 29 # print(i) 30 # time.sleep(1)
二、锁机制
1、问题的产生?
数据共享使用时可能会出现混乱,比如以下代码实现的数据共享就会出现这样的情况。
1 # *******************问题**********************开始 2 from multiprocessing import Process,Value 3 import time 4 5 def get_money(num): # 取钱 6 for i in range(100): 7 num.value -= 1 8 time.sleep(0.01) 9 10 def put_money(num): # 存钱 11 for i in range(100): 12 num.value += 1 13 time.sleep(0.01) 14 15 if __name__ == '__main__': 16 num = Value('i',100) # 数据类型+值(数据共享) 17 p = Process(target=get_money,args=(num,)) 18 p.start() 19 p1 = Process(target=put_money,args=(num,)) 20 p1.start() 21 p.join() 22 p1.join() 23 print(num.value) # 获取到子进程的num 24 # *******************问题**********************结束
2、解决问题——锁机制
(1)锁涉及两个操作:
拿钥匙,锁门:——不让别人进屋
换钥匙,开门:——让别人进屋
(2)锁的特点是:一把钥匙配一把锁
(3)锁的相关代码:
1 from multiprocessing import Lock 2 3 l = Lock() 4 5 l.acquire() # 拿走钥匙,锁门,不让其他人进屋 6 7 l.release() # 释放锁,还钥匙,开门,允许其他人进入
(4)用锁解决问题对应的代码
1 from multiprocessing import Process,Value,Lock 2 import time 3 4 def get_money(num,l): # 取钱 5 l.acquire() # 拿走钥匙,锁上门,不让其他人进来 6 for i in range(100): 7 num.value -= 1 8 time.sleep(0.01) 9 l.release() # 还钥匙,开门,允许其他人进入 10 11 def put_money(num,l): # 存钱 12 l.acquire() # 拿走钥匙,锁上门,不让其他人进来 13 for i in range(100): 14 num.value += 1 15 time.sleep(0.01) 16 l.release() # 还钥匙,开门,允许其他人进入 17 18 if __name__ == '__main__': 19 l = Lock() # 设置一把锁 20 num = Value('i',100) # 数据类型+值(数据共享) 21 p = Process(target=get_money,args=(num,l)) 22 p.start() 23 p1 = Process(target=put_money,args=(num,l)) 24 p1.start() 25 p.join() 26 p1.join() 27 print(num.value) # 获取到子进程的num
(5)模拟抢票
1 # *******************抢票**********************开始 2 from multiprocessing import Process,Lock 3 import time 4 5 6 def check(i): 7 with open("余票") as f: 8 con = f.read() 9 print("第%s个人查到余票还剩%s张" % (i,con)) 10 11 def buy_ticket(i,l): 12 # 这里的锁是保护在多进程中数据安全 13 l.acquire() 14 with open("余票") as f: 15 con = int(f.read()) 16 time.sleep(0.1) 17 18 if con > 0: 19 print('\033[31m 第%s个人买到了票\033[0m' % i) 20 con -= 1 21 else: 22 print("\033[32m 第%s个人没有买到票\033[0m" % i) 23 time.sleep(0.1) # 是指,买完票后,把余票数量重新写入数据库的延迟时间 24 25 with open("余票",'w') as f: 26 f.write(str(con)) 27 l.release() 28 29 30 if __name__ == '__main__': 31 l = Lock() 32 for i in range(10): 33 p_ch = Process(target=check,args=(i+1,)) 34 p_ch.start() 35 for i in range(10): 36 p_buy = Process(target=buy_ticket,args=(i+1,l)) 37 p_buy.start() 38 39 # *******************抢票**********************结束
三、信号机制
1、信号量
一把锁配多把钥匙。、
信号量机制比锁机制多了一个计数器,这个计数器是用来记录当前剩余几把钥匙的。
1 from multiprocessing import Semaphore 2 3 l = Semaphore(3) # 一把锁配3把钥匙 4 5 l.acquire() # 拿走一把钥匙,锁上门 6 print(123) 7 l.acquire() # 拿走一把钥匙,锁上门 8 print(456) 9 l.acquire() # 拿走一把钥匙,锁上门 10 print(789) 11 l.acquire() # 在此会阻塞,等待其他钥匙归还(释放) 12 print(111)
2、举例操作
1 # *******************信号机制——案例**********************开始 2 from multiprocessing import Semaphore,Process 3 import time 4 import random 5 6 def func(i,sem): 7 sem.acquire() 8 print('第%s个人进入小黑屋,拿了钥匙上门' % i) 9 time.sleep(random.randint(3,5)) 10 print('第%s个人出去小黑屋,还了钥匙打开门' % i) 11 sem.release() 12 13 if __name__ == '__main__': 14 sem = Semaphore(5) # 初始化一把锁5把钥匙 15 for i in range(20): 16 p = Process(target=func,args=(i,sem,)) 17 p.start() 18 # *******************信号机制——案例**********************结束
四、事件机制
1、事件机制介绍:
事件是通过is_set( )的bool值,去标识e.wait( )的阻塞状态。
当is_set( )的bool值为False时,e.wait( )是阻塞状态。
当is_set( )的bool值为True时,e.wait( )是非阻塞状态。
当使用set( )时,是把is_set的bool值变为True.
当使用clear( )时,是把is_set的bool值变为False。
1 from multiprocessing import Event 2 3 e = Event() 4 5 print(e.is_set()) # False 6 e.set() # 将is_set的bool值变为True, 将wait变为非阻塞 7 e.wait() 8 print(e.is_set()) # True 9 print(123) 10 e.clear() 11 print(e.is_set()) # False 12 e.wait() # 阻塞 13 print(456)
2、案例:
红绿灯事件。
1 # *******************事件机制——案例**********************开始 2 from multiprocessing import Process,Event 3 import time 4 5 6 def tra(e): 7 '''信号灯函数''' 8 e.set() 9 print("\033[32m 绿灯亮! \033[0m") # 红灯亮了5秒后提示绿灯亮 10 while 1: 11 if e.is_set(): # True,代表绿灯亮,那么此时代表可以过车 12 time.sleep(5) # 所以在这让灯等5秒钟,这段时间让车过 13 print('\033[31m 红灯亮! \033[0m') # 绿灯亮了5秒应该提示红灯亮 14 e.clear() # 把is_set设置为False 15 else: 16 time.sleep(5) # 此时代表红灯亮了,红灯亮5秒 17 print("\033[32m 绿灯亮! \033[0m") # 红灯亮了5秒后提示绿灯亮 18 e.set() # 将is_set设置为True 19 20 21 def Car(i,e): 22 e.wait() # 车在等红绿灯,is_set为False时不过,True时过车 23 print("第%s辆车过去了" % i) 24 25 if __name__ == '__main__': 26 e = Event() 27 traffic_light = Process(target=tra,args=(e,)) # 信号灯的进程 28 traffic_light.start() 29 for i in range(50): # 描述50辆车 30 if i % 3 == 0: 31 time.sleep(2) 32 car = Process(target=Car,args=(i+1,e,)) # 汽车的进程 33 car.start() 34 # *******************事件机制——案例**********************结束