进程池与线程池
在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。那么我们要怎么做呢?
在这里,要给大家介绍一个进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。
池:
保证计算机硬件安全的情况下提升程序的运行效率
进程池:
提前创建好固定数量的进程 后续反复使用这些进程(合同工)
线程池:
提前创建好固定数量的线程 后续反复使用这些线程(合同工)
如果任务超出了池子里面的最大进程或线程数 则原地等待
强调:
进程池和线程池其实降低了程序的运行效率 但是保证了硬件的安全!!!
concurrent.fututres 模块
ProcessPoolExecutor
类–进程池开启
实例化获得一个进程池, 参数传入一个整数,代表进程池的大小
不传的话会默认开设当前计算机CPU 个数的进程
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
# 线程池
pool = ThreadPoolExecutor(5) # 线程池线程数默认是CPU个数的五倍 也可以自定义
'''上面的代码执行之后就会立刻创建五个等待工作的线程'''
'''不应该自己主动等待结果 应该让异步提交自动提醒>>>:异步回调机制'''
# 进程池
pool = ProcessPoolExecutor(5) # 进程池进程数默认是CPU个数 也可以自定义
'''上面的代码执行之后就会立刻创建五个等待工作的进程'''
pool.submit(task, i).add_done_callback(func)
方法及属性介绍
-
异步提交任务 (submit 方法)
pool_p.submit(task,n=i)
:task
–提交的任务,逗号之后可以按照位置参数或者关键字参数传入task
所需的参数;from concurrent.futures import ProcessPoolExecutor import time pool1 = ProcessPoolExecutor(5) def task(n): print(n) time.sleep(2) if __name__ == '__main__': for i in range(5): pool1.submit(task, i) print('main process')
-
result
方法submit
方法返回的Future
对象会有一个result
方法result
方法 会返回**提交的任务最终返回的结果 **from concurrent.futures import ProcessPoolExecutor import time pool1 = ProcessPoolExecutor(5) def task(n): print(n,end=' ') time.sleep(1) if __name__ == '__main__': for i in range(5): res=pool1.submit(task, i) print(res.result()) print('main process')
-
shutdown 方法
关闭线程池,等待线程池中所有的任务全部运行结束
if __name__ == '__main__':
l = []
for i in range(10):
res=pool1.submit(task, i)
l.append(res)
pool1.shutdown()
for res in l:
print('返回值:',res.result())
print('main process')
add_done_callback
–异步回调机制
回调机制相当于给每个异步提交的任务绑定了一个"炸弹",一旦这个异步提交的任务运行到返回结果的时候,就会立刻"爆炸"
from concurrent.futures import ProcessPoolExecutor
import time
pool1 = ProcessPoolExecutor(5)
def task(n):
print('--调用函数:',n)
time.sleep(0.5)
return n ** 2
def call_back(feature):
print('!!获得函数结果:',feature.result())
if __name__ == '__main__':
for i in range(10):
res = pool1.submit(task, i)
time.sleep(0.2)
res.add_done_callback(call_back)
注意:对于add_done_callback( callback )传入的函数名callback,在定义callback函数的时候一定要写一个位置参数
这个位置参数会通过add_done_callback( callback )方法自动传入, 而且这个参数就是 调用add_done_callback方法的feature对象
ThreadPoolExecutor类–线程池的开启
方法与属性 与进程池完全一致!!!