• 并发编程:互斥锁,生产者,消费者模型


    一 守护进程:

    守护进程也就是一个进程会随着另一个进程(被守护进程)的结束而结束:

    from multiprocessing import Process
    import time
    def func(name):
        time.sleep(2)
        print('%s is running'%name)
    if __name__ == '__main__':
        # t=Process(target=func,args=('feng',))
        t=Process(target=func,kwargs={'name':'feng'})
        t.daemon=True#我们通过把子进程变成守护进程。
        t.start()
        print('zhu'.center(50,'*'))
    输出结果:***********************zhu************************
    从结果我们可以看出,主进程一结束,子进程就结束。

    二 互斥锁:保证每一个我们的子进程完整的运行完之后才会运行下一个子进程,但是在当前子进程阻塞的时候可以去进行新的子进程的创建。

    from multiprocessing import Process,Lock
    import time
    import random
    mutex=Lock()
    def task1(lock):
        lock.acquire()#不能连续的acquire,必须抢一次,释放一次才能继续抢。
        print('task1:name1')
        time.sleep(random.randint(1,2))
        print('task1:age1')
        time.sleep(random.randint(1, 2))
        print('task1:sex1')
        time.sleep(random.randint(1, 2))
        lock.release()
    def task2(lock):
        lock.acquire()
        print('task1:name2')
        time.sleep(random.randint(1, 2))
        print('task1:age2')
        time.sleep(random.randint(1, 2))
        print('task1:sex2')
        time.sleep(random.randint(1, 2))
        lock.release()
    def task3(lock):
        lock.acquire()
        print('task1:name3')
        time.sleep(random.randint(1, 2))
        print('task1:age3')
        time.sleep(random.randint(1, 2))
        print('task1:sex3')
        time.sleep(random.randint(1, 2))
        lock.release()
    if __name__ == '__main__':
        p1=Process(target=task1,args=(mutex,))
        p2=Process(target=task2,args=(mutex,))
        p3=Process(target=task3,args=(mutex,))
        p1.start()
        p2.start()
        p3.start()
    我们从multiprocessing模块导入Lock,通过Process实例化出三个对象p1,p2,p3,这三个对象在执行的时候就是三个进程,互斥锁会保证三个进程之间公平竞争cpu资源
    join与互斥锁的区别:二者原理一样,把并发变成串行,保证有序,join人为的指定顺序
    应该谁先启动谁先来用,如果使用join那么我们的顺序就固定了,必须p1先开始

    而互斥锁是所有的进程平等的争抢,谁先抢到谁先用。抢到之后运行完了一定要要释放,要不然别的进程没办法拿到锁。
    我们使用join同样可以实现一个串行的效果:
    from multiprocessing import Process
    import time
    import random
    def task1():
        print('task1:name1')
        time.sleep(random.randint(1,2))
        print('task1:age1')
        time.sleep(random.randint(1, 2))
        print('task1:sex1')
        time.sleep(random.randint(1, 2))
    def task2():
        print('task1:name2')
        time.sleep(random.randint(1, 2))
        print('task1:age2')
        time.sleep(random.randint(1, 2))
        print('task1:sex2')
        time.sleep(random.randint(1, 2))
    
    def task3():
        print('task1:name3')
        time.sleep(random.randint(1, 2))
        print('task1:age3')
        time.sleep(random.randint(1, 2))
        print('task1:sex3')
        time.sleep(random.randint(1, 2))
    if __name__ == '__main__':
        p1=Process(target=task1,)
        p2=Process(target=task2,)
        p3=Process(target=task3,)
        p1.start()
        p1.join()
        p2.start()
        p2.join()
        p3.start()
        p3.join()
    使用join实现有序输出

    三 基于互斥锁模拟抢票系统:

    互斥锁可以有选择的让一部分代码(修改共享数据的代码)串行。而join则让所有的代码都按照一个确定的顺序运行。

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

    同样的我们也可以使用join实现一个抢票系统,但是这个时候,每次只能一个人来操作,也就是说,每次只能提供一个人进行查票或则买票,其他人只有等到前一个用户退出之后
    才能进行查票或则购票,而互斥锁可以提供多个用户同时查票,单个用户购票。

    #文件db的内容为:{"count":1}
    #注意一定要用双引号,不然json无法识别
    from multiprocessing import Process,Lock
    import time,json,random
    def search():
        dic=json.load(open('db.txt'))
        print('33[43m剩余票数%s33[0m' %dic['count'])
    
    def get():
        dic=json.load(open('db.txt'))
        time.sleep(0.1) #模拟读数据的网络延迟
        if dic['count'] >0:
            dic['count']-=1
            time.sleep(0.2) #模拟写数据的网络延迟
            json.dump(dic,open('db.txt','w'))
            print('33[43m购票成功33[0m')
    
    def task(lock):
        search()
        get()
    if __name__ == '__main__':
        lock=Lock()
        for i in range(100): #模拟并发100个客户端抢票
            p=Process(target=task,args=(lock,))
            p.start()
    使用join实现每次单个用户购票

    总结:其实基于互斥锁和join这两种方式效率都是比较低的,但是互斥锁要比join效率更高,而且互斥锁可以实现CPU利用更大化,同时开启多个进程,我们可以让多个进程都查看余票数,但是这个余票数是不可靠的,因为多个进程都执行到这一步,但是最终只有一个进程能拿到这个票,也就是说大家所看到的其实是一张票。而如果我们使用join模式的话,那么只要我们能查看到票就能买到票。

    四 ICP机制:我们又称他为基于消息的机制。

    进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的

    进程之间的通信:进程之间是相互独立的,所以进程之间的通讯需要介质:管道和队列,我们优先使用队列。

    队列的通讯是一个有序的过程,先进先出,不会导致我们的信息混乱,而管道的两端都可以进行存取,所以容易造成错乱。

    进程之间的通信:
    必须找到一种介质:
    介质需要满足的条件是: 1 是所有进程共享的 2 必须是内存空间 3 这种机制需要帮我们自动处理锁的问题

    列队:队列的一些用法,其实底层就是互斥锁+管道的原理。

     队列:先进先出,里面不应该存放数据量较大的数据,又来存方进程之间沟通的消息,数据量不应该过大。
     1 共享的空间
     2 是内存空间
     3 自动处理锁的问题
    from multiprocessing import Queue
    q
    =Queue(3),最多只能put三次,这里的3受限于内存空间的大小,也就是说,maxsize是可以无限大的,但是那样没意义。 q.put()#括号里面obj,在Python中一切皆为对象。 q.put('first',block=False) q.put() q.get() q.get() q.get('first',block=True,timeout=3)#当block为True时,管道中没有东西给你来取的时候,就会一直等待,程序不会终止。 q.get('first',block=False,timeout=3)#这个时候如果管道中没有东西取,等待三秒之后就会抛出异常,我们可以使用try来处理此异常。 q.put()#括号里面obj q.put('first',block=True,timeout=3)#等3秒 q.put('first',block=True,timeout=3)其中block说的是阻塞与非阻塞的问题,而timeout只有在非阻塞的情况下运用,规定等待一段时间之后抛出异常, q.put()

     不得不感慨multiprocessing真的是一个强大的模块。。。。。。。。

    五 生产者,消费者模型:

    生产者消费者模型主要分为:生产者与消费者两大类
    
    生产者:把负责造数据的任务称为生产则,
    
    消费者:接收生产者造出的数据来作进一步处理。
    
    生产者消费者模型三要素:1 生产者, 2 消费者 , 3 队列
    
    使用场景:一定是我们的程序中出现明显的两类任务,一类人物是负责生产而另一类任务是负责处理生产的数据的
    
    
    
    好处:1 实现了生产者与消费者解耦合
    
              2 平衡了生产力与消费力,生产者可以一直不停的生产,消费者可以一直不停的处理,因为二者不再直接沟通。而是直接从阻塞队列里取,
    阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。











  • 相关阅读:
    android--------Popupwindow的使用
    virtualbox+vagrant学习-3-Vagrant Share-3-SSH Sharing
    virtualbox+vagrant学习-3-Vagrant Share-2-HTTP Sharing
    virtualbox+vagrant学习-3-Vagrant Share-1-简介
    virtualbox+vagrant学习-4-Vagrantfile-2-Configuration Version
    virtualbox+vagrant学习-4-Vagrantfile-1-简介
    virtualbox+vagrant学习-3-Vagrant Share-6-Custom Provider
    virtualbox+vagrant学习-3-Vagrant Share-5-Security
    virtualbox+vagrant学习-3-Vagrant Share-4-Vagrant Connect
    AOP
  • 原文地址:https://www.cnblogs.com/zhangsanfeng/p/8944623.html
Copyright © 2020-2023  润新知