进程池和multiprocess.Pool模块
一、为什么要有进程池
首先,创建进程需要消耗时间,销毁进程也需要时间。其次,即使开启了成千上万的进程,操作系统也不能让它们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。
进程池:定义了一个池子,在里面放上固定数量的进程,有需求来了,就拿这个池中的一个进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待认为。如果有许多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。
总结:也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程再运行。这样 不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。
二、进程池和多进程效率对比
import os import time import random from multiprocessing import Pool from multiprocessing import Process def func(i): i += 1 if __name__ == '__main__': p = Pool(5) # 创建了5个进程 start = time.time() p.map(func,range(1000))
p.close() # 是不允许再向进程池中添加任务 p.join() print(time.time() - start) # 0.35544490814208984 start = time.time() l = [] for i in range(1000): p = Process(target=func,args=(i,)) # 创建了一百个进程 p.start() l.append(p) [i.join() for i in l] print(time.time() - start) # 101.00088691711426
import os,time from multiprocessing import Pool def work(n): print('%s run' %os.getpid()) time.sleep(3) return n**2 if __name__ == '__main__': p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务 res_l=[] for i in range(10): res=p.apply(work,args=(i,)) # 同步调用,直到本次任务执行完毕拿到res,等待任务work执行的过程中可能有阻塞也可能没有阻塞 # 但不管该任务是否存在阻塞,同步调用都会在原地等着 print(res_l)
import os import time import random from multiprocessing import Pool def work(n): print('%s run' %os.getpid()) time.sleep(random.random()) return n**2 if __name__ == '__main__': p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务 res_l=[] for i in range(10): res=p.apply_async(work,args=(i,)) # 异步运行,根据进程池中有的进程数,每次最多3个子进程在异步执行 # 返回结果之后,将结果放入列表,归还进程,之后再执行新的任务 # 需要注意的是,进程池中的三个进程不会同时开启或者同时结束 # 而是执行完一个就释放一个进程,这个进程就去接收新的任务。 res_l.append(res) # 异步apply_async用法:如果使用异步提交的任务,主进程需要使用jion,等待进程池内任务都处理完,然后可以用get收集结果 # 否则,主进程结束,进程池可能还没来得及执行,也就跟着一起结束了 p.close() p.join() for res in res_l: print(res.get()) #使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get
通过进程池利用socket实现并发聊天
#Pool内的进程数默认是cpu核数,假设为4(查看方法os.cpu_count()) #开启6个客户端,会发现2个客户端处于等待状态 #在每个进程内查看pid,会发现pid使用为4个,即多个客户端公用4个进程 from socket import * from multiprocessing import Pool import os server=socket(AF_INET,SOCK_STREAM) server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) server.bind(('127.0.0.1',8080)) server.listen(5) def talk(conn): print('进程pid: %s' %os.getpid()) while True: try: msg=conn.recv(1024) if not msg:break conn.send(msg.upper()) except Exception: break if __name__ == '__main__': p=Pool(4) while True: conn,*_=server.accept() p.apply_async(talk,args=(conn,)) # p.apply(talk,args=(conn,client_addr)) #同步的话,则同一时间只有一个客户端能访问
from socket import * client=socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: msg=input('>>: ').strip() if not msg:continue client.send(msg.encode('utf-8')) msg=client.recv(1024) print(msg.decode('utf-8'))
import os import time from multiprocessing import Pool # 参数 概念 回调函数 def func(i): # 多进程中的io多, print('子进程%s:%s'%(i,os.getpid())) return i*'*' def call(arg): # 回调函数是在主进程中完成的,不能传参数,只能接受多进程中函数的返回值 print('回调 :',os.getpid()) print(arg) if __name__ == '__main__': print('---->',os.getpid()) p = Pool(5) for i in range(10): p.apply_async(func,args=(i,),callback=call) p.close() p.join()
如果在主进程中等待进程池中所有任务都执行完毕后,再统一处理结果,则无需回调函数。
from multiprocessing import Pool import time,random,os def work(n): time.sleep(1) return n**2 if __name__ == '__main__': p=Pool() res_l=[] for i in range(10): res=p.apply_async(work,args=(i,)) res_l.append(res) p.close() p.join() #等待进程池中所有进程执行完毕 nums=[] for res in res_l: nums.append(res.get()) #拿到所有结果 print(nums) #主进程拿到所有的处理结果,可以在主进程中进行统一进行处理