• python-day32(进程池,管道,数据共享)


    一. 管道

      进程间通信(IPC)  管道(不推荐使用),会导致数据不安全的情况出现,

      conn1,conn2 = Pipe 表示管道两端的连接对象,强调一点: 必须在产生Process对象之前产生管道

      主要方法:

        conn1.recv(): 接收从conn2.send(obj)对象,如果没有消息可接收,recv方法会一直阻塞,

          如果连接的另一端已经关闭,namerecv方法会抛出EOFError

        conn1.send(obj): 通过连接发送对象,obj是与序列化兼容的任意对象

      其他方法:

        conn1.close(): 关闭连接, 如果conn1被垃圾回收,将自动调用次方法

     1 from multiprocessing import Process, Pipe
     2 
     3 def f(conn):
     4     conn.send("Hello 妹妹") #子进程发送了消息
     5     conn.close()
     6 
     7 if __name__ == '__main__':
     8     parent_conn, child_conn = Pipe() #建立管道,拿到管道的两端,双工通信方式,两端都可以收发消息
     9     p = Process(target=f, args=(child_conn,)) #将管道的一段给子进程
    10     p.start() #开启子进程
    11     print(parent_conn.recv()) #主进程接受了消息
    12     p.join()
    管道的使用, 使用不当各种报错

    二. 数据共享

      Manager:进程间数据是独立的,可以借助于队列或者管道实现通信,二者都是基于消息传递的

          虽然进程间数据独立,但可以通过Manager实现数据共享

      多进程共同去处理共享数据的时候,就和我们多进程同时去操作一个文件中的数据是一样的,

      不加锁就会出现错误的结果,进程不安全的,所以也需要加锁

     1 from multiprocessing import Manager,Process,Lock
     2 def work(d,lock):
     3     with lock: #不加锁而操作共享的数据,肯定会出现数据错乱
     4         d['count']-=1
     5 
     6 if __name__ == '__main__':
     7     lock=Lock()
     8     with Manager() as m:
     9         dic=m.dict({'count':100})
    10         p_l=[]
    11         for i in range(100):
    12             p=Process(target=work,args=(dic,lock))
    13             p_l.append(p)
    14             p.start()
    15         for p in p_l:
    16             p.join()
    17         print(dic)
    Manager 模块使用

     (进程间的通信: 管道,队列,数据共享)

    三. 进程池 (重点)

      创建进程池的类: 如果指定numprocess参数为3,则进程池会从无到有创建三个进程,然后

      自始至终使用这三个进程去执行所有任务,不会开启其他进程,提高操作系统效率,减少空间的占用

      创建进程池 p = Pool(4) #四个进程 如果省略,将默认使用 cpu_count() 的值

      p.apply()  同步提交任务,直接可以收到返回值

     1 import os,time
     2 from multiprocessing import Pool
     3 
     4 def work(n):
     5     print('%s run' %os.getpid())
     6     time.sleep(1)
     7     return n**2
     8 
     9 if __name__ == '__main__':
    10     p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务
    11     res_l=[]
    12     for i in range(10):
    13         res=p.apply(work,args=(i,)) # 同步调用,直到本次任务执行完毕拿到res,等待任务work执行的过程中可能有阻塞也可能没有阻塞
    14                                     # 但不管该任务是否存在阻塞,同步调用都会在原地等着
    15         res_l.append(res)
    16     print(res_l)
    同步调用

      p.apply_async() 异步提交任务: res.get() 阻塞效果

     1 import os
     2 import time
     3 import random
     4 from multiprocessing import Pool
     5 
     6 def work(n):
     7     print('%s run' %os.getpid())
     8     time.sleep(random.random())
     9     return n**2
    10 
    11 if __name__ == '__main__':
    12     p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务
    13     res_l=[]
    14     for i in range(10):
    15         res=p.apply_async(work,args=(i,)) # 异步运行,根据进程池中有的进程数,每次最多3个子进程在异步执行,并且可以执行不同的任务,传送任意的参数了。
    16                                           # 返回结果之后,将结果放入列表,归还进程,之后再执行新的任务
    17                                           # 需要注意的是,进程池中的三个进程不会同时开启或者同时结束
    18                                           # 而是执行完一个就释放一个进程,这个进程就去接收新的任务。  
    19         res_l.append(res)
    20 
    21     # 异步apply_async用法:如果使用异步提交的任务,主进程需要使用join,等待进程池内任务都处理完,然后可以用get收集结果
    22     # 否则,主进程结束,进程池可能还没来得及执行,也就跟着一起结束了
    23     p.close() #不是关闭进程池,而是结束进程池接收任务,确保没有新任务再提交过来。
    24     p.join()   #感知进程池中的任务已经执行结束,只有当没有新的任务添加进来的时候,才能感知到任务结束了,所以在join之前必须加上close方法
    25     for res in res_l:
    26         print(res.get()) #使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get
    异步调用

        close join

      p.map()  异步提交任务,参数是可迭代对象,自带close + join

     1 import time
     2 from multiprocessing import Process,Pool
     3 
     4 
     5 def func(i):
     6     num = 0
     7     for j in range(5):
     8         num += i
     9 
    10 
    11 if __name__ == '__main__':
    12     pool = Pool(4)  #
    13     p_list = []
    14     start_time = time.time()
    15     for i in range(100):
    16         p = Process(target=func,args=(i,))
    17         p_list.append(p)
    18         p.start()
    19     [pp.join() for pp in p_list]
    20     end_time = time.time()
    21     print(end_time - start_time)
    22 
    23     s_time = time.time()
    24     pool.map(func,range(100))  #map
    25     e_time = time.time()
    26     print(e_time - s_time)
    map

     回调函数:callback

     1 import os
     2 from multiprocessing import Pool
     3 
     4 def func1(n):
     5     print('func1>>',os.getpid())
     6     print('func1')
     7     return n*n
     8 
     9 def func2(nn):
    10     print('func2>>',os.getpid())
    11     print('func2')
    12     print(nn)
    13     # import time
    14     # time.sleep(0.5)
    15 if __name__ == '__main__':
    16     print('主进程:',os.getpid())
    17     p = Pool(5)
    18     #args里面的10给了func1,func1的返回值作为回调函数的参数给了callback对应的函数,不能直接给回调函数直接传参数,他只能是你任务函数func1的函数的返回值
    19     # for i in range(10,20): #如果是多个进程来执行任务,那么当所有子进程将结果给了回调函数之后,回调函数又是在主进程上执行的,那么就会出现打印结果是同步的效果。我们上面func2里面注销的时间模块打开看看
    20     #     p.apply_async(func1,args=(i,),callback=func2)
    21     p.apply_async(func1,args=(10,),callback=func2)
    22 
    23     p.close()
    24     p.join()
    25 
    26 #结果
    27 # 主进程: 11852  #发现回调函数是在主进程中完成的,其实如果是在子进程中完成的,那我们直接将代码写在子进程的任务函数func1里面就行了,对不对,这也是为什么称为回调函数的原因。
    28 # func1>> 17332
    29 # func1
    30 # func2>> 11852
    31 # func2
    32 # 100
    View Code
    1 需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数,这是进程池特有的,普通进程没有这个机制,但是我们也可以通过进程通信来拿到返回值,进程池的这个回调也是进程通信的机制完成的。
    2 
    3 我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果
    回调函数
    其他方法:
    p.close():关闭进程池,防止进一步操作
    p.join():等待所有工作进程退出,次方法只能在close()或teminate()之后调用

    更多点击

      

      

      

      

  • 相关阅读:
    UVA 10391 STL容器的使用
    UVA 10763
    UVA 10935
    UVA 洪水
    UVA 1594 set 里面放queue
    关于STL 容器的嵌套使用, 小试牛刀
    丑数 UVA 136
    UVA 1368 DNA
    antd 上传文件控件使用方法(坑)
    mysql查询一条工单时间需要10秒。优化sql语句得以解决。
  • 原文地址:https://www.cnblogs.com/Thui/p/10039551.html
Copyright © 2020-2023  润新知