zoukankan      html  css  js  c++  java
  • python进程-守护进程原理-,互斥锁与join区别-队列-生产者消费者模式

    1.守护进程

        守护进程其实就是一个‘子进程’

        守护=》伴随

            1.守护进程会伴随主进程的代码运行完毕后而死掉

            2.守护进程内无法再开启子进程,否则抛出异常

    2.为何用守护进程:

        关键字就两个:

                进程:

                        当父进程需要将一个任务并发出去执行,需要将该任务放在一个子进程里

                守护:

                        当该子进程内的代码在父进程代码运行完毕后就没存在的意义了。

                        就应该将该子进程设置为守护进程,会在父进程代码结束后死掉

    # from multiprocessing import Process
    # import time,os
    #
    # def task(name):
    #     print('%s is running' %name)
    #     time.sleep(3)
    #
    # if __name__ == '__main__':
    #     p1=Process(target=task,args=('守护进程',))
    #     p2=Process(target=task,args=('正常的子进程',))
    #
    #     p1.daemon = True          # 一定要放到p.start()之前
    #     p1.start()
    #     p2.start()
    #
    #     print('主')     #主进程代码运行完毕,守护进程就会结束  # 一定要放到p.start()之前
    #     p1.start()
    #     p2.start()
    #
    #     print('主')     #主进程代码运行完毕,守护进程就会结束

    互斥锁:可以将要执行任务的部分代码(只涉及到修改共享数据的代码)变成串行进程操作

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

    join:是要执行任务的所有代码整体串行

    #模拟买票场景-多进程并发-互斥锁
    from multiprocessing import Process,Lock
    import json
    import os
    import time
    import random
    
    def check():
        time.sleep(1) # 模拟网路延迟
        with open('db.txt','rt',encoding='utf-8') as f:
            dic=json.load(f)
        print('%s 查看到剩余票数 [%s]' %(os.getpid(),dic['count']))
    
    def get():
        with open('db.txt','rt',encoding='utf-8') as f:
            dic=json.load(f)
        time.sleep(2)
        if dic['count'] > 0:
            # 有票
            dic['count']-=1
            time.sleep(random.randint(1,3))
            with open('db.txt','wt',encoding='utf-8') as f:
                json.dump(dic,f)
            print('%s 购票成功' %os.getpid())
        else:
            print('%s 没有余票' %os.getpid())
    
    
    def task(mutex):
        # 查票
        check()
    
        #购票
        mutex.acquire() # 互斥锁不能连续的acquire,必须是release以后才能重新acquire
        get()
        mutex.release()
    
    
    
        # with mutex:          互斥锁 简单写法
        #     get()
    
    if __name__ == '__main__':
        mutex=Lock()
        for i in  range(10):
            p=Process(target=task,args=(mutex,))
            p.start()
            # p.join()
    from multiprocessing import Process,Lock
    import json
    import os
    import time
    import random
    
    def check():
        time.sleep(1) # 模拟网路延迟
        with open('db.txt','rt',encoding='utf-8') as f:
            dic=json.load(f)
        print('%s 查看到剩余票数 [%s]' %(os.getpid(),dic['count']))
    
    def get():
        with open('db.txt','rt',encoding='utf-8') as f:
            dic=json.load(f)
        time.sleep(2)
        if dic['count'] > 0:
            # 有票
            dic['count']-=1
            time.sleep(random.randint(1,3))
            with open('db.txt','wt',encoding='utf-8') as f:
                json.dump(dic,f)
            print('%s 购票成功' %os.getpid())
        else:
            print('%s 没有余票' %os.getpid())
    
    
    def task(mutex):
        # 查票
        check()
    
        #购票
        mutex.acquire() # 互斥锁不能连续的acquire,必须是release以后才能重新acquire
        get()
        mutex.release()
    
    
    
        # with mutex:          互斥锁 简单写法
        #     get()
    
    if __name__ == '__main__':
        mutex=Lock()
        for i in  range(10):
            p=Process(target=task,args=(mutex,))
            p.start()
            # p.join()

    IPC(队列):进程间的通信,要实现进程间通信(IPC),有两种实现方式

                      multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的

    1.PIPE 管道

    2.queue:PIPE+锁

        注意:1.队列占用的是内存空间,

                 2.不应该往队列中放大数据,应该值存放数量较小的消息

                

    from multiprocessing import Queue
    
    #掌握
    # q=Queue(3) #可以指定队列大小
    # q.put('xxx')
    # q.put({'s':'sencond'})
    # q.put(['faga'])
    # q.put(4)     #设置最大3个,锁机制,到第四个时候阻塞主,直到取走一个后才能再放进一个
    #
    #
    #
    # print(q.get())
    # print(q.get())
    # print(q.get())
    # # print(q.get()) #超过取值,会阻塞
    
    #了解知识
    # q = Queue(3)  # 超时时间只有block=True才有意义   block=False不会阻塞,直接报错
    # q.put('ffa', block=True, timeout=3)  # 队列满了后 阻塞主,再来一个,等待三秒没人来取就会报错
    # q.put({'k': 'sencond'}, block=True, timeout=3)
    # q.put(['third', ], block=True, timeout=3)
    # print('===>')
    # q.put(4,block=True,timeout=3)
    
    # print(q.get(block=True,timeout=3))
    # print(q.get(block=True,timeout=3))
    # print(q.get(block=True,timeout=3))
    # print(q.get(block=True,timeout=3))
    
    
    #block=False简写版:
    q=Queue(3) #先进先出
    
    q.put_nowait('first') #q.put('first',block=False,)
    q.put_nowait(2)
    q.put_nowait(3)
    # q.put_nowait(4)
    
    print(q.get_nowait())
    print(q.get_nowait())
    print(q.get_nowait())
    print(q.get_nowait()) #掌握
    # q=Queue(3) #可以指定队列大小
    # q.put('xxx')
    # q.put({'s':'sencond'})
    # q.put(['faga'])
    # q.put(4)     #设置最大3个,锁机制,到第四个时候阻塞主,直到取走一个后才能再放进一个
    #
    #
    #
    # print(q.get())
    # print(q.get())
    # print(q.get())
    # # print(q.get()) #超过取值,会阻塞
    
    #了解知识
    # q = Queue(3)  # 超时时间只有block=True才有意义   block=False不会阻塞,直接报错
    # q.put('ffa', block=True, timeout=3)  # 队列满了后 阻塞主,再来一个,等待三秒没人来取就会报错
    # q.put({'k': 'sencond'}, block=True, timeout=3)
    # q.put(['third', ], block=True, timeout=3)
    # print('===>')
    # q.put(4,block=True,timeout=3)
    
    # print(q.get(block=True,timeout=3))
    # print(q.get(block=True,timeout=3))
    # print(q.get(block=True,timeout=3))
    # print(q.get(block=True,timeout=3))
    
    
    #block=False简写版:
    q=Queue(3) #先进先出
    
    q.put_nowait('first') #q.put('first',block=False,)
    q.put_nowait(2)
    q.put_nowait(3)
    # q.put_nowait(4)
    
    print(q.get_nowait())
    print(q.get_nowait())
    print(q.get_nowait())
    print(q.get_nowait()) 

    1.什么是生产者消费者模型

        生产者:比喻的是程序中负责产生数据的任务

        消费者:比喻的是程序中负责处理数据的任务

          生产者=》共享的介质(队列)《=消费者

    2.为何用:

        实现了生产者与消费者的解耦和,生产者可以不停的生产,消费者也可以不停的消费

        从而平衡了生产者的生产能力与消费者消费能力,提升了程序整体运行的效率

            (就是在生产和消费同时进行并实现队列通信,两者之间就需要一个机制来协调管理)

    3.什么时候用?

        当我们的程序中存在明显的两类任务,一类负责产生数据,另外一类负责处理数据

        此时就应该考虑使用生产者消费者模型来提升效率的效率

       JoinableQueue 方法

    模拟生产者和消费者环境

    from multiprocessing import JoinableQueue, Process
    import time, os, random
    
    
    def producer(name, food, q):
        for i in range(3):
            res = '%s%s' % (food, i)
            time.sleep(random.randint(1, 3))
            q.put(res)
            print('33[42m%s生产了%s33[0m' % (name, res))
    
    
    def consumer(name, q):
        while True:
            res = q.get()
            if res is None: break
            time.sleep(random.randint(1, 3))
            print('33[44m%s吃了%s33[0m' % (name, res))
            q.task_done() #告诉队列取走数据
    
    
    if __name__ == '__main__':
        q = JoinableQueue() #可以检测到队列里有多少个值,取走一个减一个
                            #有个join方法,检测队列值的值取完可以结束
        # 生产者
        p1 = Process(target=producer, args=('egon', '包子', q))
        p2 = Process(target=producer, args=('杨军', '泔水', q))
        p3 = Process(target=producer, args=('猴老师', '翔', q))
        # 消费者
        c1 = Process(target=consumer, args=('alex', q))
        c2 = Process(target=consumer, args=('wupeiqi', q))
    
        c1.daemon=True       #开启守护进程
        c2.daemon=True       #父进程结束,子进程也结束
    
        p1.start()
        p2.start()
        p3.start()
        c1.start()
        c2.start()
    
        p1.join()
        p2.join()
        p3.join()
    
        q.join() #原地等待队列里的值被取干净后,才运行下面代码。
                # 消费者进程也就应该要结束,所以需要
        print('主')
    
        #总结:
        #主进程的代码运行完毕-->(生产者运行完毕)+列队中的数据也被取干净了->消费者最后也存在意思了 #告诉队列取走数据
    
    
    if __name__ == '__main__':
        q = JoinableQueue() #可以检测到队列里有多少个值,取走一个减一个
                            #有个join方法,检测队列值的值取完可以结束
        # 生产者
        p1 = Process(target=producer, args=('egon', '包子', q))
        p2 = Process(target=producer, args=('杨军', '泔水', q))
        p3 = Process(target=producer, args=('猴老师', '翔', q))
        # 消费者
        c1 = Process(target=consumer, args=('alex', q))
        c2 = Process(target=consumer, args=('wupeiqi', q))
    
        c1.daemon=True       #开启守护进程
        c2.daemon=True       #父进程结束,子进程也结束
    
        p1.start()
        p2.start()
        p3.start()
        c1.start()
        c2.start()
    
        p1.join()
        p2.join()
        p3.join()
    
        q.join() #原地等待队列里的值被取干净后,才运行下面代码。
                # 消费者进程也就应该要结束,所以需要
        print('主')
    
        #总结:
        #主进程的代码运行完毕-->(生产者运行完毕)+列队中的数据也被取干净了->消费者最后也存在意思了

    总结:       守护进程:deamon=True

                      互斥锁:Lock

                        队列-PIPE+锁: Queue():q.put()  q.get()           

                         JoinableQueue :task_done告诉队列取走数据

                                                                   join 原地等待队列中的数据取完后再运行下面代码,阻塞

  • 相关阅读:
    all、any函数 分类: python 20130424 11:21 542人阅读 评论(0) 收藏
    九九乘法表 分类: python 小练习 20130416 09:26 193人阅读 评论(0) 收藏
    and or 逻辑运算符用法 分类: python 20130419 14:40 660人阅读 评论(0) 收藏
    #小练习 合并首字母相同的男孩、女孩姓名 分类: python 小练习 20130425 17:26 281人阅读 评论(0) 收藏
    #小练习 类与继承 分类: python 小练习 20130426 15:27 175人阅读 评论(0) 收藏
    python模块内置函数 分类: python 20130415 15:17 297人阅读 评论(0) 收藏
    #小练习:计算Fibonacci数列的前10项 分类: python 小练习 20130422 11:50 289人阅读 评论(0) 收藏
    ubuntu开启SSH服务 分类: ubuntu 20130415 17:04 326人阅读 评论(0) 收藏
    使用reduce函数 分类: python 20130418 20:34 316人阅读 评论(0) 收藏
    利用SecureCRT上传、下载文件(使用sz与rz命令) 分类: ubuntu 20130423 10:39 231人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/Marcki/p/10111929.html
Copyright © 2011-2022 走看看