开进程和开线程都需要消耗资源,只不过线程相比进程耗费的资源较小,但是计算机的硬件是有限制的,我们不能无限制的去开启进程或者线程.进程池和线程池能帮助我们在计算机承受的范围内最大限度的利用计算机
什么是池
在保证计算机硬件安全的情况下最大限度的利用计算机
池其实是降低了程序的运行效率,但是保证了计算机硬件的安全
怎么使用池
我们首先定义一个池子,在里边放入固定数量的进程或线程,只要有任务来了,就派一个进程或线程去处理任务,如果固定数量的进程或线程使用完了,那么接下来的任务就在外面等待,直到有进程或线程的任务执行完毕,外面的任务才可以拿到空闲的进程或线程执行,这样我们既可以同时使用多个进程或线程,又可以保证计算机硬件不会因为任务过多而导致死机等情况
注意:池子中的进程或线程的数量是固定的,可以自己定义数量,但是里边的进程或线程是不会动态改变的.例如工厂中有5个工人,一堆任务过来,他们只能同时执行5个,一个工人做完一个任务之后再做另一个任务,任务在变,但是工人是不会变的,即虽然任务在变,但是进程或线程只会创建一次,执行多少任务还是那几个,这样也节省了反复开闭进程线程的时间
#1 介绍 concurrent.futures模块提供了高度封装的异步调用接口 ThreadPoolExecutor:线程池,提供异步调用 ProcessPoolExecutor: 进程池,提供异步调用 Both implement the same interface, which is defined by the abstract Executor class. #2 基本方法 #submit(fn, *args, **kwargs) 异步提交任务 #map(func, *iterables, timeout=None, chunksize=1) 取代for循环submit的操作 #shutdown(wait=True) 相当于进程池的pool.close()+pool.join()操作 wait=True,等待池内所有任务执行完毕回收完资源后才继续 wait=False,立即返回,并不会等待池内的任务执行完毕 但不管wait参数为何值,整个程序都会等到所有任务执行完毕 submit和map必须在shutdown之前 #result(timeout=None) 取得结果 #add_done_callback(fn) 回调函数 # done() 判断某一个线程是否完成 # cancle() 取消某个任务
1 from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor 2 import time 3 import os 4 5 # pool = ThreadPoolExecutor(5) # 创建线程池对象,参数可以不传,默认参数是当前计算机cpu个数*5 6 pool = ProcessPoolExecutor(5) # 创建进程池对象,参数可以不传,默认参数是当前计算机cpu个数 7 8 def task(i): 9 print('线程%s,进程号:%s'%(i,os.getpid())) 10 time.sleep(1) # 模拟IO 11 return i 12 13 ''' 14 提交任务的方式有两种 15 同步:提交任务之后,原地等待任务的返回值,期间不做任何事 16 异步:提交任务之后,不等待返回结果,继续执行下一行代码 17 ''' 18 19 def call_back(n): 20 print('回调函数拿到了返回值%s'%n.result()) # 返回值+.result()取得结果 21 ''' 22 异步提交任务怎么拿到返回值: 23 异步回调机制:当异步提交的任务有结果后,会自动触发回调函数的执行 24 ''' 25 26 if __name__ == '__main__': 27 t_list = [] 28 for i in range(20): 29 t = pool.submit(task,i) 30 t.add_done_callback(call_back) # 异步回调机制 31 print(os.cpu_count()) # 当前计算机是8核计算机