如果每个任务使用一个进程,每处理一个任务都会伴随着一个进程的创建、运行、销毁,如果进程的运行时间越短,创建和销毁的时间所占的比重就越大,显然,我们应该尽量避免创建和销毁进程本身的额外开销,提高进程的运行效率。我们可以用进程池来减少进程的创建和开销,提高进程对象的复用。
Pool(processes=None, initializer=None, initargs=(), maxtasksperchild=None)
Pool对象有下面几个主要的方法用于将任务分配到进程池中去,它们分别是
下面是一个例子:
def task_short(num):
time.sleep(3)
print("I am task: {0}\n".format(num))
def task_long(num):
while True:
print("I am task: {0}\n".format(num))
time.sleep(1)
if __name__ == "__main__":
pool = Pool(processes=5)
# 异步任务
pool.apply_async(task_short, args=(10, ))
# 同步任务
pool.map(task_long, range(10))
print("main process")
该例子创建了一个有5个worker的进程池,并先将1个任务task_short异步地加入进程池中运行,然后又将10个任务task_long同步地加入进程池中。
由于task_short需要3秒才能执行完,所以一开始task_long任务可用的worker进程只有4个。3秒后task_short完成,进程池会自动再加载1个task_long任务交给刚刚空闲的那个worker进程执行。
由于task_long任务永远不会结束,所以其他剩余的任务5到9都没有机会执行。
通过上面的例子,我们发现进程池不适合执行那些永远不会完成的任务,比如后台服务,因为没有worker进程执行完成的话,其他的进程就永远不会被执行。
multiprocessing.dummy里面也有一个Pool对象,它其实就是线程的封装,使用起来和multiprocessing的Pool非常类似。
因为多进程适合计算密集的多任务,多线程适合IO密集的多任务,所以在代码里面使用下面两句,需要的时候注释掉其中之一,可以做到进程模型和线程模型的一键切换。
如果你不知道自己的程序是计算密集的还是IO密集的,就切换下试试,哪个性能表现好,就用哪个。
from multiprocessing.dummy import Pool # 多线程
from multiprocessing import Pool # 多进程
本文地址已经归档到github,您可以访问下面的链接获得。
代码地址
如果觉得本文对您有帮助,敬请点赞。