通过学习,我们使用各种方法实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。
一、锁的基础使用
1.1多个进程抢占数据资源
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
1.2使用锁维护执行顺序
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 end
上面这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。
三、抢票小程序实列(锁实现数据安全和高效率)
3.1多进程同时抢票实例
我们以模拟抢票为例,来看看数据安全的重要性。
# 文件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
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
购票成功
并发运行,效率高,但竞争写同一文件,数据写入错乱
3.2 使用join方法来实现数据安全
如果使用join方法的话,那这样就是成了一个串行的概念了,这样只能保证数据的安全性,但是程序的效率问题并没有解决
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
没有票了
*3.3 使用锁机制Lock来实现数据安全
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。
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抢票成功
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
票已经售空!!!!
原文地址:https://www.cnblogs.com/xichenHome/p/11569043.html