• 守护进程,进程安全,IPC进程间通讯,生产者消费者模型


    1.守护进程(了解)
    2.进程安全(*****)
    互斥锁
    抢票案例
    3.IPC进程间通讯
    manager
    queue(*****)
    4.生产者消费者模型

    守护进程
    指的也是一个进程,可以守护着另一个进程
    一个进程a 设置为b的守护进程 当b结束时 a会立马结束自己 不管任务是否执行完毕
    使用场景: 例如qq进程 有一个下载任务 交给了一个子进程 但是过程中 qq退出了 下载进程也可以随之关闭了

    *** p.daemon=True 将p子进程设置为主进程的守护进程 必须放在开启进程之前设置***


    进程安全问题
    当多个进程要同时操作同一个资源时,就可能出现问题
    例如:
    只有一台答应机大那会很多打印任务 如果不加以控制 可能造成打印结果错乱
    解决方案1:加 join 把原本并发的任务变成串行执行
    但是如此一来 进程与顺序就不再平等 顺序已经固定死
    最终的解决方案就是加锁
    使用Lock来实例化产生一把锁
    但是要保证每个进程访问的都是同一把锁
    在访问共享资源前 加锁
    访问完毕后一定要解锁
    不能多次执行acquire 一次acquire对应一次release
    acquire 是一个阻塞函数 会一直等到锁被释放(release调用)才会继续执行

    lock=Lock()
    lock.acquire() 锁定
    lock.release() 解锁
    # from multiprocessing import Process,Lock
    # import time,random
    #
    # def task1(lock):
    #     lock.acquire()
    #     print('惺惺相惜想')
    #     time.sleep(random.randint(1,2))
    #     lock.release()
    #
    #
    # def task2(lock):
    #     lock.acquire()
    #     print('xxx')
    #     time.sleep(random.randint(1, 2))
    #     lock.release()
    #
    # def task3(lock):
    #     lock.acquire()
    #     print('1234')
    #     time.sleep(random.randint(1, 2))
    #     lock.release()
    #
    #
    # if __name__ == '__main__':
    #     lock=Lock()
    #     p1=Process(target=task1,args=(lock,))
    #     p2 = Process(target=task2, args=(lock,))
    #     p3 = Process(target=task3, args=(lock,))
    #
    #     p1.start()
    #     p2.start()
    #     p3.start()
    加锁


    加锁之后 并发又变成了串行了 不过与join不同的是 没有规定顺序 谁先抢到谁先执行


    问题:一旦加锁 效率降低 不加锁数据要错乱

    在使用锁的时候 无可避免的会降低效率
    需要找到一个最合适的地方加上锁
    你锁住的代码越少效率越高

    join是让整个进程中的代码全部串行 而锁可以部分代码串行
    粒度(被锁住的代码量)越小 效率越高

    互斥锁:互相排斥其他进程


    IPC 进程间通讯
    进程与进程之间 内存是物理隔离的 无法直接通讯

    1.使用一个交换文件 在硬盘上创建一个文件 不同进程之间共享这个文件
    优点:交换的数据量几乎没有限制
    缺点:速度慢
    2.系统开辟一块共享内存 来供进程间交换数据
    优点:速度快
    缺点:交换的数据量不能太大
    3.管道
    优点:封装了文件的打开 关闭等操作
    缺点:速度慢 单向传输 编程的复杂度较高
    4.socket
    不仅可用于与远程计算机中的进程通讯 还可以用于与本地进程通讯
    基于内存的速度快
    # from multiprocessing import  Process,Manager,Lock
    #
    # import time
    #
    #
    #
    # def task(dic,lock):
    #     lock.acquire()
    #     i = dic["num"]   # 3  3  3
    #     time.sleep(0.3) #2  2  2
    #     dic["num"] = i - 1
    #     lock.release()
    #
    # if __name__ == '__main__':
    #     # 共享内存管理器
    #     m = Manager()
    #     # 在共享内存区域 创建了一个字典
    #     dic = m.dict({"num":3})
    #
    #     lock = Lock()
    #     # 将处于共享内存区域的字典传给子进程
    #     p =Process(target=task,args=(dic,lock))
    #     p1 = Process(target=task, args=(dic,lock))
    #     p2 = Process(target=task, args=(dic,lock))
    #
    #
    #     p.start()
    #     p1.start()
    #     p2.start()
    #
    #     p.join()
    #     p1.join()
    #     p2.join()
    #
    #
    #
    #     print(dic["num"])
    IPC
    Manager 共享内存管理器
    开启一个共享的内存区域 可以是列表 字典 array数组
    没有处理进程安全问题 需要自己加锁

    queue 队列也是一个容器
    特点:先进先出
    支持进程间共享
    自动出来了进程安全问题(加锁)
    例如:迅雷下载 先添加的任务一定先开始执行

    堆栈:
    特点:先进后出
    例如:函数的执行 吃薯片 最上面的最先吃


    put()会阻塞,直到队列里面有位置为止
    get()也会阻塞,直到队里里面有数据为止
    put(obj,block=True,timeout),block为阻塞的意思,默认为阻塞状态,
    timeout等待超时,只有在block为True时有效

    # from multiprocessing import  Process,Manager,Queue
    #
    # import time
    #
    #
    #
    # def task(q):
    #     num = q.get() # 3
    #     time.sleep(0.5)
    #     q.put(num-1)
    #
    #
    # if __name__ == '__main__':
    #
    #     q = Queue()
    #     q.put(3)
    #     # 将处于共享内存区域的字典传给子进程
    #     p =Process(target=task,args=(q,))
    #     p1 = Process(target=task, args=(q,))
    #     p2 = Process(target=task, args=(q,))
    #
    #
    #     p.start()
    #     p1.start()
    #     p2.start()
    #
    #     p.join()
    #     p1.join()
    #     p2.join()
    #
    #
    #
    #     print(q.get())
    QUE队列


    生产者消费者模型
    模型即解决某个问题的套路
    问题:
    生产者负责产生数据
    消费者处理数据
    当消费者与生产者的能力不匹配时,必须一放要等待另一方 这样效率就变低了


    1.将原本由同一个进程完成的 两个(生产和消费) 拆分为两个不交给两个不同的角色(进程)来完成
    2.由于进程间内存相互隔离 所以需要为两个角色之间提供一个共享的数据容器
    3.生产 将生产完成的数据 放入容器中
    4.消费者从 容器中取出数据来处理

    生产者消费者模型的优点:
    1.平衡了生产者和消费者之间的能力差异 提高处理效率
    2.降低了双方耦合度

    学习并发 的两个核心问题 安全性 和 效率

    from multiprocessing import  Process,Queue
    import time,random
    
    # 生产者
    def xiaomi_factory(name,q):
        for i in  range(1,6):
            time.sleep(random.randint(1,3))
            phone = "这是%s生产的 小米9_%s" % (name,i)
            print("生产者 生产了%s" % phone)
            # 方到柜台 即 存储到队列中
            q.put(phone)
    
    # 消费者
    def buy_mi9(q):
        for i in range(10):
            # 从队列中取出需要被处理的数据(phone)
            time.sleep(random.randint(1, 2))
            phone = q.get()
            print("消费者 消费了%s" % phone)
    
    if __name__ == '__main__':
        # 共享数据的队列
        q = Queue()
    
        # 生产者
        p1 = Process(target=xiaomi_factory,args=("北京公司",q))
        p2 = Process(target=xiaomi_factory,args=("上海公司",q))
        p1.start()
        p2.start()
    
    
        # 消费者
        c1 = Process(target=buy_mi9,args=(q,))
        c1.start()
    生产者消费者模型
  • 相关阅读:
    Javascript:window.close()不起作用?
    为什么全部width:100%浏览器边缘存在留白?
    hello world
    【Vue】在Vue事件中是如何使用event对象的?
    【Vue】特殊属性is
    【Vue】过滤器
    【Vue源码】Vue不能检测到对象属性的添加或删除
    【VueRouter】vue路由跳转打开新窗口
    【VueRouter】切换路由后,新页面滚动到顶部或保持原先的滚动位置——scrollBehavior
    【VueRouter】前端路由的两种模式
  • 原文地址:https://www.cnblogs.com/gengbinjia/p/10489621.html
Copyright © 2020-2023  润新知