zoukankan      html  css  js  c++  java
  • day29-2 进程加锁

    进程安全问题

    1.当并发的多个任务要同时操作同一个资源,就会造成数据错乱的问题。

    多个进程共享同一打印终端

    import random
    import time
    from multiprocessing import Process
    
    
    def task1():
        time.sleep(random.random())
        print('task1 run ------')
        time.sleep(random.random())
        print('task1 stop ------')
    
    
    def task2():
        time.sleep(random.random())
        print('task2 run +++++')
        time.sleep(random.random())
        print('task2 stop +++++')
    
    
    if __name__ == '__main__':
        p1 = Process(target=task1)
        p2 = Process(target=task2)
    
        p1.start()
        p2.start()
    -----------------------------------------------------------------------------
    # p1和p2两个子进程并发运行,效率高,但竞争同一打印终端,带来了打印错乱的问题,
    task2 run +++++
    task1 run ------
    task2 stop +++++
    task1 stop ------
    

    多个进程共享同一文件,模拟抢票

    # 文件db.json内容为:{"count":1},多用户共享同一个文件
    import json
    from multiprocessing import Process, Lock
    
    
    def show():
        with open('db.json', 'r') as f:
            data = json.load(f)
            print('33[31m剩余票数%s33[0m' % data['count'])
    
    
    def buy():
        with open('db.json', 'r') as f:
            data = json.load(f)
            if data['count'] > 0:
                data['count'] -= 1
                time.sleep(0.1)  # 模拟写数据的网络延迟
                with open('db.json', 'w') as fw:
                    json.dump(data, fw)
                    print('33[31m购票成功33[0m')
    
    
    def task():
        show()
        buy()
    
    
    if __name__ == '__main__':
        lock = Lock()
        for i in range(10):  # 模拟并发10个客户抢票
            p = Process(target=task)
            p.start()
    -----------------------------------------------------------------------------
    # 由于在多进程并发执行,共享同一文件,竞争数据造成错乱,出现一张票多人购票成功的现象
    

    2.解决方法:将并发操作公共资源的代码,由并发变为串行,解决安全问题,但是牺牲了效率

    • 串行方式1:直接使用join()函数

      缺点:将任务中的所有代码全都串行,此时还不如不要开进程。多个进程之间原本公平竞争,join是强行规定了执行顺序

    • 串行方式2:互斥锁

      原理:将要操作的公共资源的代码锁起来,以保证同一时间只能有一个进程执行这部分代码

    # 模拟抢票
    from multiprocessing import Process, Lock
    import time, json
    
    
    def search():
        dic = json.load(open('db.json'))
        print('33[43m剩余票数%s33[0m' % dic['count'])
    
    
    def get():
        dic = json.load(open('db.json'))
        time.sleep(0.1)  # 模拟读数据的网络延迟
        if dic['count'] > 0:
            dic['count'] -= 1
            time.sleep(0.2)  # 模拟写数据的网络延迟
            json.dump(dic, open('db.json', 'w'))
            print('33[43m购票成功33[0m')
    
    
    def task(lock):
        # 仅将部分代码串行
        search()
        lock.acquire()  # 加锁
        get()
        lock.release()  # 解锁
    
    
    if __name__ == '__main__':
        lock = Lock()  # 创建锁,必须保证锁只有一把
        for i in range(10):  # 模拟并发10个客户端抢票
            p = Process(target=task, args=(lock,))
            p.start()
    

    锁其实只是给执行的代码加了限制,本质上是一个标志True或False。被锁住的代码越多,锁的粒度越大,效率越低。所以为提高进程的效率,应尽量锁住越少的代码

  • 相关阅读:
    [LeetCode] Dungeon Game
    [LeetCode] Maximal Rectangle
    [LeetCode] Scramble String -- 三维动态规划的范例
    [LeetCode] Palindrome Partitioning II
    [LeetCode] Palindrome Partitioning
    [LeetCode] Interleaving String
    [LeetCode] Longest Valid Parentheses -- 挂动态规划羊头卖stack的狗肉
    JPA将查询结果转换为DTO对象
    EOS签名R值过大导致报错"is_canonical( c ): signature is not canonical"
    比特币中P2SH(pay-to-script-hash)多重签名的锁定脚本和解锁脚本
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11129118.html
Copyright © 2011-2022 走看看