经过学习,咱们使用各类方法实现了程序的异步,让多个任务能够同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受咱们控制。尽管并发编程让咱们能更加充分的利用IO资源,可是也给咱们带来了新的问题:当多个进程使用同一份数据资源的时候,就会引起数据安全或顺序混乱问题。python
from multiprocessing import Process import os import time import random def work(n): print(f'{n,os.getpid()}is running') time.sleep(random.random()) print(f'{n,os.getpid()} is end') if __name__ == '__main__': for i in range(1,4): p = Process(target=work,args=(i,)) p.start()
(1, 4212)is running
(2, 8856)is running
(3, 5680)is running
(3, 5680) is end
(1, 4212) is end
(2, 8856) is end编程
from multiprocessing import Process,Lock import os import time import random def work(n,lock): lock.acquire() print(f'{n,os.getpid()}is running') time.sleep(random.random()) print(f'{n,os.getpid()} is end') lock.release() if __name__ == '__main__': lock = Lock() for i in range(1,4): p = Process(target=work,args=(i,lock)) p.start()
(1, 13304)is running
(1, 13304) is end
(2, 7524)is running
(2, 7524) is end
(3, 14552)is running
(3, 14552) is endjson
上面这种状况虽然使用加锁的形式实现了顺序的执行,可是程序又从新变成串行了,这样确实会浪费了时间,却保证了数据的安全。小程序
咱们以模拟抢票为例,来看看数据安全的重要性。安全
# 文件db的内容为:{"count":1} # 注意必定要用双引号,否则json没法识别 # 并发运行,效率高,但竞争写同一文件,数据写入错乱 from multiprocessing import Process,Lock import time,json,random def search(i): time.sleep(1) dic=json.load(open('ad.txt')) print('子进程%s查看剩余票数%s' %(i,dic['count'])) def get(): dic=json.load(open('ad.txt')) time.sleep(1) # 模拟读数据的网络延迟 if dic['count'] >0: dic['count']-=1 time.sleep(0.2) # 模拟写数据的网络延迟 json.dump(dic,open('ad.txt','w')) print('购票成功') def task(i): search(i) get() if __name__ == '__main__': for i in range(1,15): # 模拟并发15个客户端抢票 p=Process(target=task,args=(i,)) p.start()
子进程2查看剩余票数1
子进程3查看剩余票数1
子进程12查看剩余票数1
子进程7查看剩余票数1
子进程11查看剩余票数1
子进程13查看剩余票数1
子进程9查看剩余票数1
子进程8查看剩余票数1
子进程6查看剩余票数1
子进程14查看剩余票数1
子进程5查看剩余票数1
子进程1查看剩余票数1
子进程10查看剩余票数1
子进程4查看剩余票数1
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功网络
并发运行,效率高,但竞争写同一文件,数据写入错乱并发
若是使用join方法的话,那这样就是成了一个串行的概念了,这样只能保证数据的安全性,可是程序的效率问题并无解决dom
from multiprocessing import Process,Lock import time,json,random def search(): dic=json.load(open('db')) print('剩余票数%s' %dic['count']) def get(): dic=json.load(open('db')) if dic['count'] >0: dic['count']-=1 time.sleep(0.2) # 模拟写数据的网络延迟 json.dump(dic,open('db','w')) print('购票成功') def task(): search() get() if __name__ == '__main__': for i in range(1,15): # 模拟并发15个客户端抢票 p=Process(target=task) p.start() p.join()
子进程1查看剩余票数1
购票成功
子进程2查看剩余票数0
没有票了
子进程3查看剩余票数0
没有票了
子进程4查看剩余票数0
没有票了
子进程5查看剩余票数0
没有票了
子进程6查看剩余票数0
没有票了
子进程7查看剩余票数0
没有票了
子进程8查看剩余票数0
没有票了
子进程9查看剩余票数0
没有票了
子进程10查看剩余票数0
没有票了
子进程11查看剩余票数0
没有票了
子进程12查看剩余票数0
没有票了
子进程13查看剩余票数0
没有票了
子进程14查看剩余票数0
没有票了异步
加锁能够保证多个进程修改同一块数据时,同一时间只能有一个任务能够进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。学习
import json import time from multiprocessing import Process, Lock def check(): with open('db.txt','r',encoding='utf8') as fr: res = json.load(fr) return res def buy(i): with open('db.txt','r',encoding='utf8') as fr: res = json.load(fr) time.sleep(1) if res['count'] > 0: res['count'] -= 1 with open('db.txt','w',encoding='utf8') as fw: json.dump(res,fw) print(f'进程{i}抢票成功') time.sleep(0.5) # 模拟网络io else: print(f'票已经售空!!!!') def test(i,lock): res = check() print(f'还剩{res["count"]}张票!') lock.acquire() # 至关于锁头。锁住 buy(i) lock.release() # 释放锁头 if __name__ == '__main__': lock = Lock() # 写在这里是为了每个进程都拿到的是同一把锁 for i in range(1,10):# 并发模拟10个子进程同时抢票 p = Process(target=test,args=(i,lock)) p.start() # 进程锁,是把锁住的代码编程了串行 # join 是把全部的子进程编程了串行
还剩1张票! 还剩1张票! 还剩1张票! 还剩1张票! 还剩1张票! 还剩1张票! 还剩1张票! 还剩1张票! 还剩1张票! 进程5抢票成功 票已经售空!!!! 票已经售空!!!! 票已经售空!!!! 票已经售空!!!! 票已经售空!!!! 票已经售空!!!! 票已经售空!!!! 票已经售空!!!!