• Day34 python基础--并发编程基础3


    一,进程之间通信,简称:IPC:inter-process-communication

      概念:

        1.多个进程之间有一些固定的通信内容(一些信号)

        2.实现方式:socket基于文件家族通信

        3.进程之间虽然内存不共享,但是可以通信的

          Lock,Semaphore,Event 都会进行进程之间的通信,只不过这些通信的内容我们不能改变

      

      进程队列:先进先出 ****

    import queue
    from multiprocessing import Queue
    q = Queue()    #若不设置,则对列长度不限制
    q = Queue(2)   #设置队列长度,队列满了会阻塞
    
    #put()与put_nowait()
    q.put()   #若队列已满,数据进不去,并阻塞
    q.put_nowait(3) #若队列已满,进不去队列,则报错,并丢弃本次数据
    
    #get()与get_nowait()
    q.get()  #若队列为空,或取值不存在,则阻塞
    q.get_nowait(3)   #如果get队列,队列为空,或取值不存在,则报错
    
    #empty()与full()  慎用,在多进程对一个队列操作时,不准!
    q.empty():查看队列是否为空
    q.full():查看队列是否为满
    
    
    #nowait用法
    try:
        print(q.get_nowait())  
    except queue.Empty:
        print('empty')
    #例:主进程与子进程通过进程队列传递数据
    from mulitprocessing import Process,Queue
    def consume(q):
        print(q.get())  #取值
        q.put('abc')    #存值
    if __name__ == '__main__':
        q = Queue()
        p = Process(target=consume,args=(q,))
        p.start()
        q.put({'123':123})  #存值
        p.join()  #等待子进程执行完成
        print(q.get())   #取值

      

      进程队列应用:生产者消费者模型

    #做饭吃饭的例子
    import time
    import random
    from multiprocessing import Queue,Process
    def consumer(q,name):  #处理数据/消费者
        while True:
            food = q.get()
            if food is None:break
            print('%s吃了一个%s'%(name,food))
            time.sleep(random.uniform(0.5,1))
    
    def producer(q,name,food):  #获取数据/生成者
        for i in range(10):
            time.sleep(random.uniform(0.3,0.8))
            print('%s生产了%s%s'%(name,food,i))
            q.put(food+str(i))
    
    if __name__ == '__main__':
        q = Queue()
        c1 = Process(target=consumer,args=(q,'alex'))
        c2 = Process(target=consumer,args=(q,'wusir'))
        # c1.daemon = True
        c1.start()
        c2.start()
        p1 = Process(target=producer,args=(q,'taibai',''))
        p2 = Process(target=producer,args=(q,'egon',''))
        p1.start()
        p2.start()
        p1.join()
        p2.join()
        q.put(None)    #有几个consumer就需要在最后放几个none
        q.put(None)

      进程队列之joinablequeue模块:

        joinablequeue是一个类,包含put(),get(),task_done(),join()方法

    import time
    import random
    from multiprocessing import Queue,Process
    from multiprocessing import JoinableQueue
    def consumer(q,name):  #处理数据
        while True:
            food = q.get()
            print('%s吃了一个%s'%(name,food))
            time.sleep(random.uniform(0.5,1))
            q.task_done()  #向q.join()发送一次信号,证明一个数据已经被取走了
    
    def producer(q,name,food):  #获取数据
        for i in range(10):
            time.sleep(random.uniform(0.3,0.8))
            print('%s生成%s%s'%(name,food,i))
            q.put(food+str(i))  #生产数据并存值到进程队列
    
    if __name__ == '__main__':
        q = JoinableQueue()
        c1 = Process(target=consumer,args=(q,'alex'))
        c1.daemon = True  #消费者进程设置为守护进程
        c2 = Process(target=consumer,args=(q,'wusir'))
        c2.daemon = True #消费者进程设置为守护进程
        c1.start()
        c2.start()
        p1 = Process(target=producer,args=(q,'taibai',''))
        p2 = Process(target=producer,args=(q,'egon',''))
        p1.start()
        p2.start()
        p1.join()  #生产者进程执行完成前阻塞
        p2.join()  #生产者进程执行完成前阻塞
        q.join()   #生产完毕后,使用此方法进行阻塞,直到队列中所有项目均被处理(即:ask_done的值为0)
        #当队列中的数据被处理完后,结束阻塞,消费者程序随着主进程代码完成而结束

      二,管道  **

        1.队列是基于管道实现

        2.管道是基于socket、pickle实现的

        3.管道与队列的区别

          队列:进程之间数据安全,严格控制数据进出(管道+锁实现简便的IPC机制)

          管道:进程之间数据是不安全的,且存取数据复制

        4.pipe的端口管理:

          pipe的端口管理不会随着某一个进程的关闭而关闭,pipe的端口属于系统资源,需要手动释放

          操作系统来管理进程对这个端口的使用

          操作系统管理pipe端口,每当手动关闭一个端口计算-1,直到所有可以传值的端口关闭,剩余一个端口的时候,系统报错,我们可以利用异常处理对报错信息进行处理并关闭子进程。

    from multiprocessing import Pipe
    left,right = Pipe()
    left.send(12345)   #管道中的存值与取值,send,recv通过pickel和socket实现
    print(right.recv())
    from multiprocessing import Pipe,Process
    def consumer(left,right):
        left.close()   #关闭子进程right端口
        while True:
            try:
                print(right.recv())  #当子进程取不到值时,并可以Pipe可以接受传值的端口都被关闭时,则报错
            except EOFError:  #利用报错,进行异常处理,以结束子进程
                break
    if __name__ == '__main__':
        left, right = Pipe()
        Process(target=consumer, args=(left, right)).start()
        right.close()   #关闭主进程right端口
        for i in range(10):
            left.send('饭菜%s'%i)
        left.close()   #当数据存取完成是,关闭left端口,否则子程序的pipe端口管理会认为,数据还没有存取完毕,子进程会进入阻塞状态

      

      三,进程池  *****

        1:为什么要有进程池?

          开启过多的进程并不能提高你的效率,反而会降低效率

        2.进程任务的概念:

          计算密集型:充分占用cpu,多进程可以充分利用多核

            适合开启多进程,但是不适合开启很多多进程

          IO密集型:大部分时间都在阻塞队列,而不是在运行状态中

            根本不适合开启多进程

        3.进程池的创建

    #实例化 传参数(进程的个数) 进程个数默认为cpu个数 或 为1,一般为os.cpu_count() + 1
    p = Pool()
    #提交任务
        #同步提交func到一个子进程中执行
            ret = p.apply(func,args=(i,))
            #返回值:子进程对应函数的返回值
            #一个一个顺序执行,并没有任何并发效果
        #异步提交func到一个子进程中执行       
            ret = p.apply(apply_async,args=(i,))
            #没有返回值,要想所有任务能够顺利的执行完毕
                p.close()   #关闭进程池,用户不能再向这个池中提交任务了
                p.join()   #必须先close再join,阻塞直到进程池中所有任务执行完毕
            #有返回值的情况下
                ret.get()#get不能在提交任何之后立刻执行,应该先提交所有任务,再通过get得到返回值
            #map()方法
                #异步提交的简化版本
                #自带close和join方法
    #例:进程池与多进程的效率对比
    import time
    from multiprocessing import Pool,Process
    def func(num):
        print('做了第%s件衣服'%num)
    
    if __name__ == '__main__':
        #以进程池的形式执行500个任务
        strat = time.time()
        p = Pool(4)
        for i in range(500):
            p.apply_async(func,args=(i,))
        p.close()
        p.join()
        print(time.time() - strat)
    
        #以多进程的形式执行100个任务
        strat = time.time()
        p_lst = []
        for i in range(100):
            p = Process(target=func,args=(i,))
            p.start()
            p_lst.append(p)
        for p in p_lst:
            p.join()
        print(time.time() - strat)
    #以完全同步的方式提交任务(apply)
    import os
    import time
    from multiprocessing import Pool
    
    def task(num):
        time.sleep(1)
        print('%s:%s'%(num,os.getpid()))
        return num**2  #进程池有IPC机制,可以直接return
    
    if __name__ == '__main__':
        p = Pool(4)   
        for i in range(20):
            ret = p.apply(task,args=(i,))  #提交任务的方法,同步提交(自带join阻塞)
            print(ret)    #任务逐个提交并完成后再返回
    #以完全异步的方式提交任务(apply_async)
    import os
    import time
    from multiprocessing import Pool
    
    def task(num):
        time.sleep(1)
        print('%s:%s'%(num,os.getpid()))
        return num**2
    if __name__ == '__main__':
        p = Pool(4)   #默认值为os.cpu_count() or 1 ,一般为os.cpu_count()+1
        res_lst = []
        for i in range(20):
            ret = p.apply_async(task,args=(i,))
            res_lst.append(ret)
        for res in res_lst:  #异步方式取返回值
            print(res.get())
  • 相关阅读:
    选择排序
    java面试题08
    java面试题07
    java面试题06
    java面试题05
    oop.1
    4
    3
    Struts1中actionform和action属于MVC哪一层
    mysql查询时间段的所有数据
  • 原文地址:https://www.cnblogs.com/lianyeah/p/9682020.html
Copyright © 2020-2023  润新知