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。被锁住的代码越多,锁的粒度越大,效率越低。所以为提高进程的效率,应尽量锁住越少的代码

  • 相关阅读:
    LOJ #6669 Nauuo and Binary Tree (交互题、树链剖分)
    BZOJ 4734 UOJ #269 [清华集训2016]如何优雅地求和 (多项式)
    UOJ #268 BZOJ 4732 [清华集训2016]数据交互 (树链剖分、线段树)
    Codeforces 1276C/1277F/1259F Beautiful Rectangle (构造)
    UOJ #164 [清华集训2015]V (线段树)
    python – time.sleep – 睡眠线程
    GIL(全局解释器锁)与互斥锁
    python theading线程开发与加锁、信号量、事件等详解
    python装饰器概念与应用
    python中for循环的底层实现机制 迭代
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11129118.html
Copyright © 2011-2022 走看看