zoukankan      html  css  js  c++  java
  • Python程序中的进程操作-进程同步(multiprocess.Lock)

    尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。

    一、进程同步

    多个进程同时执行,为了相互制约各进程对资源的访问,使得各个进程的执行相互同步。

    在我的理解里,进程同步也算是进程间通讯(ipc)的一种手段。

    二、为什么需要进程同步

    多进程会引发抢占资源的问题,为了解决这个问题就需要各进程之间相互同步,控制进程对关键资源的访问。

    在C语言中实现进程同步的方式有很多,比如:信号量,锁机制等。

    例子: 演示多进程资源抢占问题

    import os
    import time
    import random
    from multiprocessing import Process
    
    def work(n):
        print('%s: %s is running' %(n,os.getpid()))
        time.sleep(random.random())
        print('%s:%s is done' %(n,os.getpid()))
    
    if __name__ == '__main__':
        for i in range(3):
            p=Process(target=work,args=(i,))
            p.start()
    

    三、Python中实现进程同步

    1. 首先from multiprocessing import Lock
    2. 在主进程中,实例化得到锁,lock = Lock(),并传给子进程
    3. 在子进程中通过上锁和解锁实现对多进程对资源的控制。lock.acquire()上锁,lock.release()解锁

    演示:通过Python锁机制控制资源的访问

    def work(lock,n):
        print(f"等待开锁 进程{n}")
        # 上锁
        lock.acquire()     # 当上锁之后别的进程无法访问,会阻塞住
        print(f'进程{n} pid: %s is running' % ( os.getpid()))
        time.sleep(random.random())
        print(f'进程{n} pid: %s is done' % (os.getpid()))
        # 开锁
        lock.release()
    
    if __name__ == '__main__':
        lock=Lock() # 实例化得到锁
        for i in range(3):
            p=Process(target=work,args=(lock,i))
            p.start()
    

    等待开锁 进程1
    进程1 pid: 8696 is running
    等待开锁 进程0
    等待开锁 进程2
    进程1 pid: 8696 is done
    进程0 pid: 14264 is running
    进程0 pid: 14264 is done
    进程2 pid: 22724 is running
    进程2 pid: 22724 is done

    根据结果可以发现,在上锁之前的代码。多进程是并发访问的,但上锁之后,直到解锁后才能有第二个人访问。以此类推。就好像上厕所排队一样,进去一个人关上门锁上,第二个人等着。

    但是看完你会有个疑问,那被锁上的代码,每个进程在访问的时候不就是串行的依次在访问嘛。

    确实,锁机制 保证了数据的安全,但牺牲掉效率.

    四、多进程模拟同时抢票

    # 文件db的内容为:{"count":1}
    # 注意一定要用双引号,不然json无法识别
    # 并发运行,效率高,但竞争写同一文件,数据写入错乱
    from multiprocessing import Process,Lock
    import time,json,random
    def search():
        dic=json.load(open('db'))
        print('剩余票数%s' %dic['count'])
    
    def get():
        dic=json.load(open('db'))
        time.sleep(0.1)  # 模拟读数据的网络延迟
        if dic['count'] >0:
            dic['count']-=1
            time.sleep(0.2)  # 模拟写数据的网络延迟
            json.dump(dic,open('db','w'))
            print('购票成功')
    
    def task():
        search()
        get()
    
    if __name__ == '__main__':
        for i in range(100):  # 模拟并发100个客户端抢票
            p=Process(target=task)
            p.start()
    

    上述代码,你会发现多个进程在同时抢票,相互抢占文件资源,每个进程都把文件读入到内存中进行抢票。实际上,资源只能被一个人占有,这就会引发问题

    4.1 通过锁控制进程资源访问

    def search():
        time.sleep(1)
        with open("db","w",encoding="utf8") as f:
            data = json.load(f)
            print(f'还剩{data["count"]}')
    
    def get():
        with open('db','rt',encoding='utf-8') as f:
            res = json.load(f)
        time.sleep(1)  # 模拟网络io
        if res['count'] > 0:
            res['count'] -= 1
            with open('db', 'w', encoding='utf-8') as f:
                json.dump(res, f)
                print(f'进程{os.getpid()} 抢票成功')
            time.sleep(1.5)  # 模拟网络io
        else:
            print('票已经售空啦!!!!!!!!!!!')
    
    def task(lock):
        print(f"进程:{os.getpid()}  正在抢票中。。。")
    
        # 上锁     每个进程都会访问一遍,所以加锁就等于上锁到解锁这段代码是串行的
        lock.acquire()  # 当上锁之后别的进程无法访问,会阻塞住
        get()
        # 开锁
        lock.release()
    
    if __name__ == '__main__':
        # 创建锁
        lock = Lock()
    
        pro_list = []
        # 创建进程
        for i in range(10):
            p = Process(target=task, args=(lock,))
            p.start()
            pro_list.append(p)
        # 回收进程
        for i in range(10):
            pro_list[i].join()
    

    总结

    进程同步理论上应该是进程间通讯中的一部分,是一个大话题,每个语言也都有实现进程同步的需求。需要将各个进程对资源的访问加以限制。在各个语言中也都有限制。这里目前只介绍了这一种进程同步的方法。

    锁机制 是把锁住的代码变成了串行,保证了数据的安全,但牺牲掉效率.

  • 相关阅读:
    【Oracle】实体化视图
    安装Linux Centos系统硬盘分区方法
    .NET基础一
    【MySQL】无法启动mysql服务(位于本地计算机上)错误1067,进程意外中止
    Linux基础一
    SQL Server中生成100万行8位纯数字的随机数(转)
    SQL Server配置数据库邮件
    SQL点点滴滴_聪明的小写法(持续更新中)
    过去的2017和已经到来的2018
    【Oracle】PL/SQL Developer使用技巧(持续更新中)
  • 原文地址:https://www.cnblogs.com/XuChengNotes/p/11529599.html
Copyright © 2011-2022 走看看