zoukankan      html  css  js  c++  java
  • python互斥锁

    互斥锁

    进程之间数据隔离, 但是多个进程可以共享同一块数据,比如共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,而共享带来的是竞争,竞争带来的结果就是错乱,如下

    from multiprocessing import Process
    import time
    import os
    
    def task(name):
        print('%s 上厕所 [%s]' %(name ,os.getpid()))
        time.sleep(1)
        print('%s 上完厕所 [%s]' %(name ,os.getpid()))
    
    
    if __name__ == '__main__':
        for i in range(3):
            p=Process(target=task, args=('进程%s' %i,))
            p.start()
    
    ----------输出结果
    进程2 上厕所 [8076]
    进程0 上厕所 [5176]
    进程1 上厕所 [2100]
    进程2 上完厕所 [8076]
    进程0 上完厕所 [5176]
    进程1 上完厕所 [2100]
    

    如何控制,就是加锁处理。而互斥锁的意思就是互相排斥,如果把多个进程比喻为多个人,互斥锁的工作原理就是多个人都要去争抢同一个资源:卫生间,一个人抢到卫生间后上一把锁,

    其他人都要等着,等到这个完成任务后释放锁,其他人才有可能有一个抢到......所以互斥锁的原理,就是把并发改成串行,降低了效率,但保证了数据安全不错乱  

    from multiprocessing import Process, Lock
    import time
    import os
    
    def task(name,mutex):
        mutex.acquire()
        print('%s 上厕所 [%s]' %(name ,os.getpid()))
        time.sleep(1)
        print('%s 上完厕所 [%s]' %(name ,os.getpid()))
        mutex.release()
    
    
    if __name__ == '__main__':
        mutex = Lock()
        for i in range(3):
            p=Process(target=task, args=('进程%s' %i,mutex))
            p.start()
    
    ----输出结果
    进程0 上厕所 [5340]
    进程0 上完厕所 [5340]
    进程1 上厕所 [7796]
    进程1 上完厕所 [7796]
    进程2 上厕所 [7860]
    进程2 上完厕所 [7860]
    

      

    模拟抢票练习

    多个进程共享同一文件,我们可以把文件当数据库,用多个进程模拟多个人执行抢票任务

    # db.txt
    # {"count": 2}
    
    from multiprocessing import Process,Lock
    import json
    import time
    import os
    
    def query_ticket(name):
        time.sleep(1)
        with open('db.txt','r',encoding="utf-8") as f:
            d = json.load(f)
            print('[%s] 查看到剩余票数 [%s]'% (name, d['count']))
    
    def buy_ticket(name):
        time.sleep(1)
        with open('db.txt','r', encoding="utf-8") as f:
            d = json.load(f)
            if d.get('count') >0 :
                d['count'] -= 1
                time.sleep(1)
                json.dump(d, open('db.txt','w',encoding='utf-8'))
                print('<%s> 购票成功' % name)
            else:
                print('没有多余的票,<%s> 购票失败' % name)
    
    def task(name,mutex):
        query_ticket(name)
        mutex.acquire()
        buy_ticket(name)
        mutex.release()
    
    if __name__ == '__main__':
        mutex = Lock()
        print('开始抢票了……')
        for i in range(5):
            p = Process(target=task, args=('进程%s' %i,mutex))
            p.start()
    

      

     输出结果

    开始抢票了……
    [进程0] 查看到剩余票数 [2]
    [进程1] 查看到剩余票数 [2]
    [进程2] 查看到剩余票数 [2]
    [进程4] 查看到剩余票数 [2]
    [进程3] 查看到剩余票数 [2]
    <进程0> 购票成功
    <进程1> 购票成功
    没有多余的票,<进程2> 购票失败
    没有多余的票,<进程4> 购票失败
    没有多余的票,<进程3> 购票失败
    

      

      

    互斥锁与join

    使用join可以将并发变成串行,互斥锁的原理也是将并发变成串行,那我们直接使用join就可以了啊,为何还要互斥锁

    from multiprocessing import Process,Lock
    import json
    import time
    
    def query_ticket(name):
        time.sleep(1)
        with open('db.txt','r',encoding="utf-8") as f:
            d = json.load(f)
            print('[%s] 查看到剩余票数 [%s]'% (name, d['count']))
    
    
    def buy_ticket(name):
        time.sleep(1)
        with open('db.txt','r', encoding="utf-8") as f:
            d = json.load(f)
            if d.get('count') > 0 :
                d['count'] -= 1
                time.sleep(1)
                json.dump(d, open('db.txt','w',encoding='utf-8'))
                print('<%s> 购票成功' % name)
            else:
                print('没有多余的票,<%s> 购票失败' % name)
    
    def task(name):
        query_ticket(name)
        buy_ticket(name)
    
    if __name__ == '__main__':
        print('开始抢票了……')
        for i in range(5):
            p = Process(target=task, args=('进程%s' % i,))
            p.start()
            p.join()
    
    ----------------输出结果--------------
    开始抢票了……
    [进程0] 查看到剩余票数 [2]
    <进程0> 购票成功
    [进程1] 查看到剩余票数 [1]
    <进程1> 购票成功
    [进程2] 查看到剩余票数 [0]
    没有多余的票,<进程2> 购票失败
    [进程3] 查看到剩余票数 [0]
    没有多余的票,<进程3> 购票失败
    [进程4] 查看到剩余票数 [0]
    没有多余的票,<进程4> 购票失败

    发现使用join将并发改成穿行,确实能保证数据安全,但问题是连查票操作也变成只能一个一个人去查了,很明显大家查票时应该是并发地去查询而无需考虑数据准确与否,

    此时join与互斥锁的区别就显而易见了,join是将一个任务整体串行,而互斥锁的好处则是可以将一个任务中的某一段代码串行,比如只让task函数中的buy_ticket任务串行

    def task(name,mutex):
        query_ticket(name)
        mutex.acquire()
        buy_ticket(name)
        mutex.release()
    

    总结

    加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行地修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。

    虽然可以用文件共享数据实现进程间通信,但问题是:

    1、效率低(共享数据基于文件,而文件是硬盘上的数据)

    2、需要自己加锁处理

    因此我们最好找寻一种解决方案能够兼顾:

    1、效率高(多个进程共享一块内存的数据)

    2、帮我们处理好锁问题。

    这就是mutiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道。

    队列和管道都是将数据存放于内存中,而队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,因而队列才是进程间通信的最佳选择。

  • 相关阅读:
    年度回忆录(?——2011.01)
    我在学英语
    技能冷却
    抗锯齿
    在cocos2dx 2.x FPS 等参数
    手指效果
    cocos2dx 简单OpenGL 画图
    cocos2dx tile map瓦片地图的黑线及地图抖动解决方案
    C++操作SQLite数据库
    精灵点击移动
  • 原文地址:https://www.cnblogs.com/xiao-apple36/p/9460709.html
Copyright © 2011-2022 走看看