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的区别:

  1. jion是人为地指定顺序,而互斥锁是大家平等争抢,一个人拿到锁,其余人都等待

  2. jion只 能将一个进程的代码整体串行,而互斥锁可以将局部串行,局部仅仅代表对共享
    数据修改的那一部分代码

    lock.acquire()
    ......
    lock . release()
    

    强调:

    1. 一定要在操作完毕后释放锁
    2. 重斥锁lock. acquire()不能连续执行
    3. 锁不要轻易的使用,容易造成死锁现象(我们写代码一般不会用到,都是内部封装好的)
    4. 锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理即可)
posted @ 2020-04-23 20:38  祥SHAO  阅读(196)  评论(0)    收藏  举报