• 并发编程之互斥锁


    互斥锁

    锁在IT界都是非常重要的,不但在Python中出现,尤其是数据库中得锁更多,
    比如:表锁、行锁、悲观锁、乐观锁、进程锁、互斥锁、递归锁、可重入锁、死锁等。

    互斥锁是什么?

    将并发变成串行 虽然牺牲了程序的执行效率 但是保证了数据的安全

    互斥锁概念

    同一时间运行一个进程上一把锁,就是Lock。那么我们加锁的意义在哪呢?
    加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,
    即串行的修改。虽然我们的程序运行速度是慢了,但牺牲速度却保证了数据安全

    同一时间允许多个进程上多把锁 就是[信号量Semaphore]
    信号量是锁的变形:实际实现是 计数器+锁,同时允许多个进程上锁

    互斥锁的作用

    互斥锁Lock:互斥锁就是进程的相互排斥
    谁先抢到自由,谁就上锁该资源内容,这样做可以保证数据的同步性。
    注意:多个锁一起上锁,不开锁会造成死锁,上锁和释放锁是一对

    什么时候使用互斥锁

    多个程序同时操作一份数据的时候容易产生数据错乱
    为了避免数据错乱,我们需要使用互斥锁

    如何使用互斥锁

    如何使用?
        导入模块 form multiprocessing import Process,Lock
        lock = Lock()   # 变量名创建一个锁
        lock.acquire()  # 上锁
        lock.release()  # 释放锁
    上锁谁抢到谁使用,其他人等着使用完才能使用
    
    '''
    锁相关的知识
    	行锁:针对行数据加锁 同一时间只能一个人操作
    	表锁:针对表数据加锁 同一时间只能一个人操作
    	锁的应用范围很广 但是核心都是为了保证数据的安全!!!
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    做一个简单案例试试

    	'简单案例'
    from multiprocessing import Process,Lock
    import time
    '''使用锁的目的就是为了保证安全'''
    def task(i,lock):
        lock.acquire()  # 上锁
        print('进程%s进来了' % i)
        time.sleep(1)
        print('进程%s走了' % i)
        lock.release()  # 释放锁
        '''只要上锁了,就一定别忘了最后释放锁,否则的话,别的进程永远进不来'''
    
        '''
            加上锁就一定好吗?虽然保证了数据的安全,但是呢执行效率降低了,
            所以只适用于相应适配的场景,
        '''
    
    # 使用锁就是为了安全
    if __name__ == '__main__':
        lock = Lock()
        ll = []
        for i in range(3):
            p = Process(target=task,args =(i+1,lock))
            p.start()
            ll.append(p)
    
        for j in ll:
            j.join()
    
        print('主线程')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    模拟简易版12306抢票、查票、买票

    import time, random, json
    from multiprocessing import Process, Lock
    import multiprocessing
    # 导入模块
    
    写入系统票数
    pl = {'ticket_num':5}
    with open(r'data.json','w',encoding='utf-8')as f:
    	json.dump(pl,f,ensure_ascii=False)
    
    
    '查票'
    def search(name):
        with open(r'data.json','r',encoding='utf-8')as f:
            data = json.load(f)
    
        print(f"{name}查看票,目前剩余:{data.get('ticket_num')}")
    
    
    '买票'
    def buy(name):
        # 先查询票数
        with open(r'data.json','r',encoding='utf-8')as f:
            data = json.load(f)
    
        '模拟网络延迟'
        time.sleep(random.randint(1,3))  #
    
        '判断当前是否有票'
        if data.get('ticket_num') > 0:
            data['ticket_num'] -= 1
            with open(r'data.json','w',encoding='utf-8')as f1:
                json.dump(data,f1,ensure_ascii=False)
    
            print(f"{name}抢票成功!")
        else:
            print(f"{name}很抱歉暂无票了")
    
    def run(name):
        search(name)
        buy(name)
    
    if __name__ == '__main__':
        for i in range(10):
            p = Process(target=run,args=(f"用户{i}",))
            p.start()
    
    '''这里输出结果是10个人都抢到票了,所以在这种情况下我们就得用互斥锁!'''
    
    print('============以下使用了互斥锁的代码================')
    
    '查票'
    def search(name):
        with open(r'data.json','r',encoding='utf-8')as f:
            data = json.load(f)
    
        print(f"{name}正在查票,当前剩余:{data.get('ticket_num')}张票")
    
    
    
    '买票'
    def buy(name):
        # 需要先查询是否有票
        with open(r'data.json','r',encoding='utf-8')as f:
            data = json.load(f)
    
        # 模拟延迟
        time.sleep(random.randint(1,3))
    
        # 判断当前是否有票
        if data.get('ticket_num') > 0:
            data['ticket_num'] -= 1
            with open(r'data.json','w',encoding='utf-8')as f1:
                json.dump(data,f1,ensure_ascii=False)
            print(f"用户{name},购票成功!")
        else:
            print(f"用户{name},sorry,当前暂未有票哦")
    
    def run(name,lock):
        search(name)
        # 只需要把买票环节变成串行即可
        lock.acquire()  # 上锁
        buy(name)
        lock.release()  # 释放锁
    
    if __name__ == '__main__':
    	'互斥锁在主进程中产生一把 交给多个子进程使用'
    	'''
        Lock互斥锁,进程之间数据是不共享的
        但是Lock对象底层是通过socket来互相发送数据,不管多少进程,都是同一个Lock锁
        '''
        lock = Lock()  # 创建一把锁
        for i in range(10):
            p = Process(target=run,args=(f"用户:{i}", lock))
            p.start()
    
    '''此时使用互斥锁就使有用户没有抢到票了'''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
  • 相关阅读:
    Hadoop大数据系统架构(深入浅出)
    Vue中使用pdf.js实现在线预览pdf文件流
    docker 在容器外执行某个容器内的某个命令
    C/C++之自定义类型(结构体,位段,联合体,枚举)详解
    HTTP协议,HTTP模块,express框架
    谷粒商城 高级篇 (十八) --------- 购物车
    vue3-3-响应式数据与watch属性
    评测回顾 | 天空卫士以人为本的数据防泄露系统
    【MATLAB 入门手册】基本操作与矩阵输入
    低代码开发那些事儿
  • 原文地址:https://blog.csdn.net/achen_m/article/details/133935000