python 中 multiprocessing.pool
模块里有 Pool
类用于进程池管理,Pool
实例中一些比较重要的方法:
apply_async(func, args, kwargs, callback)
- 往进程池异步提交任务,即任务提交到进程池后可以不用等任务结果可以继续往下运行;与其对立的是任务提交后,提交任务的进程会被阻塞直到任务被执行完返回结果
- 参数func是必须的,args用于提供给 func的参数,args类型为
元组
, kwargs 也是提供给 func函数的参数, callback 任务执行完后立刻执行的回调函数,callback函数禁止执行任何阻塞操作
map_async(func, iterable, chunksize, callback)
- 参数 chunksize 、 callback 是可选的
- 将可迭代对象iterable的每一个元素作为参数传递给func并异步地执行函数,返回结果是
AsyncResult
类的实例 - 如果提供 callback 参数,当返回结果变得可用时立即执行 callback 函数
close( )
- 关闭进程池防止进一步操作,关闭后将不再接受任务
join( )
- 等待所有工作进程退出,join( ) 只能在close( )方法或terminate( )方法调用后再调用
往进程池里扔任务里调用 apply_async()
方法,该方法第一个参数传递的是函数名,如果传入一个函数,函数将不会并发地执行;比如有个无参函数名字为 doMatch
,但往 apply_async()
方法传递的第一个参数如果是doMatch()
,那么提交到进程池的任务将不会并发执行
如果往apply_async()
方法传递的是函数而不是函数名,提交的任务将不会被并发执行,并且返回结果也是错误的
以下是未正确提交任务到进程池的代码
import ctypes
import datetime
import random
import time
from multiprocessing import Queue
from multiprocessing.pool import Pool
from multiprocessing import Value
def doMatch():
s = "0123456789abcdefghijklmnopqrstuvwxyz"
index = random.randint(0, len(s) - 4)
time.sleep(1)
return s[index:index + 2]
if __name__ == '__main__':
param = "0123456789abcdefghijklmnopqrstuvwxyz"
val = Value(ctypes.c_uint32, 1)
index = 1
queue = Queue()
# 测试单进程执行 doMatch() 函数30次需要的时间
start = datetime.datetime.now()
for i in range(30):
print("single process:\t{}".format(doMatch()))
finish = datetime.datetime.now()
print("\n单线程执行花费的时间为:\t{}".format(finish - start))
# 测试9个进程的进程池执行 doMatch() 函数30次需要的时间
reslist = []
pool1 = Pool(9)
start = datetime.datetime.now()
for i in range(30):
res = pool1.apply_async(doMatch())
# e = entry(param)
# res = pool1.apply_async(e.exec, callback=e.display)
reslist.append(res)
pool1.close()
pool1.join()
finish = datetime.datetime.now()
# print("result = \n{}".format(reslist))
for res in reslist:
print(res)
print("9个进程的进程池执行花费的时间为:\t{}".format(finish - start))
# 测试3组3个进程的进程池执行 doMatch() 函数30次需要的时间
pool2 = Pool(3)
pool3 = Pool(3)
pool4 = Pool(3)
pools = [pool2, pool3, pool4]
index = 1
reslist = []
start = datetime.datetime.now()
for j in range(len(pools)):
for i in range(10):
# e = entry(param)
# pools[j].apply_async(e.exec)
asyncresult = pools[j].apply_async(doMatch())
reslist.append(asyncresult)
pools[j].close()
for j in range(len(pools)):
pools[j].join()
finish = datetime.datetime.now()
print("3个3个进程的进程池执行花费的时间为:\t{}".format(finish - start))
for result in reslist:
print(result)
运行结果:
修改传递给 apply_async()
的func参数为函数名再执行的结果:
总结 :
往进程池里提交任务时需要提交要执行的函数名,不能直接向函数调用那样直接提交这个函数及参数;
如果提交的任务需要额外带参数, apply_async() 的第二个参数用于接收提交任务所需要的参数,因此可以传递两个参数给 apply_async() 方法,第二个参数的类型要求为元组;
apply_async() 方法返回的结果为 AsyncResult 的实例,可以使用 get() 方法获取异步执行的结果