88.互斥锁
互斥锁
一、概念
多个进程操作同一份数据的时候,会出现数据错乱的问题。进程之间的数据不共享,但可共享同一资源,所以访问同一文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争的结果就会产生错乱
二、案例
from multiprocessing import Process
import random, time
def task1():
time.sleep(random.randint(1, 3))
print('task1:姓名,001')
time.sleep(random.randint(1, 3))
print('task1:年龄,34')
time.sleep(random.randint(1, 3))
print('task1:性别:男')
def task2():
time.sleep(random.randint(1, 3))
print('task2:姓名,002')
time.sleep(random.randint(1, 3))
print('task2:年龄,34')
time.sleep(random.randint(1, 3))
print('task2:性别:男')
def task3():
time.sleep(random.randint(0, 2))
print('task3:姓名,003')
time.sleep(random.randint(0, 2))
print('task3:年龄,34')
time.sleep(random.randint(0, 2))
print('task3:性别:男')
if __name__ == '__main__':
p1 = Process(target=task1)
p2 = Process(target=task2)
p3 = Process(target=task3)
p1.start()
p2.start()
p3.start()
task1:姓名,001
task2:姓名,002
task3:姓名,003
task3:年龄,34
task3:性别:男
task1:年龄,34
task1:性别:男
task2:年龄,34
task2:性别:男
从结果可以看出并发运行,效率虽然高,但并发竞争资源带来了打印信息错乱。
三、解决方法
那么如何控制,就是加锁处理。而互斥锁的意思就是互相排斥,我们可以把多个进程比喻多个人,互斥锁的工作原理就是多个人去争抢共同的一个资源:如多个人要上同一个卫生间,一个人抢到卫生间后上一把锁,其他人都有外面等着,等到这个人完成后解锁后,其他人又可以去争夺。所以互斥锁的原理,就是把某一功能并发改串行,虽然降低了效率,但保证了数据安全不错乱。
from multiprocessing import Process, Lock
import random, time
def task1(lock):
lock.acquire() # 获得锁
time.sleep(random.randint(1, 3))
print('task1:姓名,001')
time.sleep(random.randint(1, 3))
print('task1:年龄,34')
time.sleep(random.randint(1, 3))
print('task1:性别:男')
lock.release() # 释放锁
def task2(lock):
lock.acquire()
time.sleep(random.randint(1, 3))
print('task2:姓名,002')
time.sleep(random.randint(1, 3))
print('task2:年龄,34')
time.sleep(random.randint(1, 3))
print('task2:性别:男')
lock.release()
def task3(lock):
lock.acquire()
time.sleep(random.randint(0, 2))
print('task3:姓名,003')
time.sleep(random.randint(0, 2))
print('task3:年龄,34')
time.sleep(random.randint(0, 2))
print('task3:性别:男')
lock.release()
if __name__ == '__main__':
mutex = Lock()
p1 = Process(target=task1, args=(mutex,))
p2 = Process(target=task2, args=(mutex,))
p3 = Process(target=task3, args=(mutex,))
p1.start()
p2.start()
p3.start()
task3:姓名,003
task3:年龄,34
task3:性别:男
task2:姓名,002
task2:年龄,34
task2:性别:男
task1:姓名,001
task1:年龄,34
task1:性别:男
这样子就不会错乱了。
强调:必须是lock.acquire()一次,然后lock.release()释放一次,才能继续lock.acquire(),不能连续的lock.acquire()
四、互斥锁与join()的区别
大前提:二者的原理都是一样,都是将并发变成串行,从而保证有序
区别一:join是按照人为指定的顺序执行,而互斥锁是所有进程平等地竞争,谁先抢到谁先执行。
区别二:互斥锁可以让一部分代码(修改共享数据的代码)串行,而join只能将代码整体串行。
来看一个抢票的小例子:
# db.json文件中的内容为{"count": 100}
from multiprocessing import Process,Lock
import json ,time
import random
def search(name):
dic=json.load(open('db.json','r',encoding='utf-8'))
time.sleep(random.randint(0,2))#模拟网络延迟
print('%s查到剩余的票数为%s张'%(name,dic['count']))
def get(name):
dic = json.load(open('db.json', 'r', encoding='utf-8'))
time.sleep(0.3)#模拟网络延迟
if dic['count']>0:
time.sleep(0.1)#模拟网络延迟
print('%s成功买到了剩下的第%s票'%(name,dic['count']))
dic['count'] -= 1
json.dump(dic,open('db.json','w',encoding='utf-8'))
def rob_ticket(name ,lock):
search(name)
with lock: #相当于获得了lock.acquire(),执行代码体完,自动执行lock.release()
get(name)
if __name__ == '__main__':
lock=Lock()
for i in range(100):
name='路人%s'%i
p=Process(target=rob_ticket,args=(name,lock))
p.start()
五、总结
互斥锁:用来将并发编程串行,牺牲了效率而保证了数据安全
互斥锁与jion的区别:
-
jion是人为地指定顺序,而互斥锁是大家平等争抢,一个人拿到锁,其余人都等待
-
jion只 能将一个进程的代码整体串行,而互斥锁可以将局部串行,局部仅仅代表对共享
数据修改的那一部分代码lock.acquire() ...... lock . release()
强调:
- 一定要在操作完毕后释放锁
- 重斥锁lock. acquire()不能连续执行
- 锁不要轻易的使用,容易造成死锁现象(我们写代码一般不会用到,都是内部封装好的)
- 锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理即可)