• 并发编程二


    一、守护进程
    主进程创建守护进程
      其一:守护进程会在主进程代码执行结束后就终止
      其二:守护进程内无法再开启子进程,否则抛出异常:
    注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止

    示例代码:
    from multiprocessing import Process
    import time


    def task(name):
    print('%s is running' % name)
    time.sleep(3)

    if __name__ == '__main__':
    obj = Process(target=task, args=('egon',))
    obj.daemon=True
    obj.start() # 发送信号给操作系统
    print('主')

    二、互斥锁
    进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,
    而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理
    强调:必须是lock.acquire()一次,然后 lock.release()释放一次,才能继续lock.acquire(),不能连续的lock.acquire()
    互斥锁vs join的区别一:
    大前提:二者的原理都是一样,都是将并发变成串行,从而保证有序
    区别:join是按照人为指定的顺序执行,而互斥锁是所以进程平等地竞争,谁先抢到谁执行

    示例代码:
    def task1(lock):
    lock.acquire() #
    print('task1:名字是egon')
    time.sleep(random.randint(1,3))
    print('task1:性别是male')
    time.sleep(random.randint(1,3))
    print('task1:年龄是18')
    lock.release()

    def task2(lock):
    lock.acquire()
    print('task2:名字是alex')
    time.sleep(random.randint(1,3))
    print('task2:性别是male')
    time.sleep(random.randint(1,3))
    print('task2:年龄是78')
    lock.release()

    def task3(lock):
    lock.acquire()
    print('task3:名字是lxx')
    time.sleep(random.randint(1,3))
    print('task3:性别是female')
    time.sleep(random.randint(1,3))
    print('task3:年龄是30')
    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()



    加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。
    虽然可以用文件共享数据实现进程间通信,但问题是:
    1.效率低(共享数据基于文件,而文件是硬盘上的数据)
    2.需要自己加锁处理

    三、IPC通信机制

    因此我们最好找寻一种解决方案能够兼顾:
    1、效率高(多个进程共享一块内存的数据)
    2、帮我们处理好锁问题。
    这就是mutiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道。
    1 队列和管道都是将数据存放于内存中
    2 队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,
    我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,
    而且在进程数目增多时,往往可以获得更好的可获展性。

    示例:
    q=Queue(3)
    q.put('first')
    q.put({'second':None})
    q.put('三')

    # q.put(4) #阻塞
    print(q.get())
    print(q.get())
    print(q.get())



    强调:
    1、队列用来存成进程之间沟通的消息,数据量不应该过大
    2、maxsize的值超过的内存限制就变得毫无意义

    四、生产者与消费者模型(重要)

    该模型中包含两类重要的角色:
    1、生产者:将负责造数据的任务比喻为生产者
    2、消费者:接收生产者造出的数据来做进一步的处理,该类人物被比喻成消费者


    实现生产者消费者模型三要素
    1、生产者
    2、消费者
    3、队列

    什么时候用该模型:
    程序中出现明显的两类任何,一类任务是负责生产,另外一类任务是负责处理生产的数据的

    该模型的好处:
    1、实现了生产者与消费者解耦和
    2、平衡了生产力与消费力,即生产者可以一直不停地生产,消费者可以不停地处理,因为二者
    不再直接沟通的,而是跟队列沟通


    示例代码:
    import time
    import random
    from multiprocessing import Process,Queue

    def consumer(name,q):
    while True:
    res=q.get()
    time.sleep(random.randint(1,3))
    print('33[46m消费者===》%s 吃了 %s33[0m' %(name,res))


    def producer(name,q,food):
    for i in range(5):
    time.sleep(random.randint(1,2))
    res='%s%s' %(food,i)
    q.put(res)
    print('33[45m生产者者===》%s 生产了 %s33[0m' %(name,res))


    if __name__ == '__main__':
    #1、共享的盆
    q=Queue()

    #2、生产者们
    p1=Process(target=producer,args=('egon',q,'包子'))
    p2=Process(target=producer,args=('刘清政',q,'泔水'))
    p3=Process(target=producer,args=('杨军',q,'米饭'))

    #3、消费者们
    c1=Process(target=consumer,args=('alex',q))
    c2=Process(target=consumer,args=('梁书东',q))


    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()
  • 相关阅读:
    JQuery缓冲加载图片插件lazyload.js的使用方法
    CSS3阴影 box-shadow的使用和技巧总结
    HTML符号大全
    TouchSlide
    响应式图片的3种解决方案
    ECMAScript arguments 对象
    call() 方法 和 apply()方法详解
    字体图标 iconfont cssfont
    响应式样式
    1-微信小程序创建项目
  • 原文地址:https://www.cnblogs.com/zhaodafa/p/8944717.html
Copyright © 2020-2023  润新知