concurrent.futures这个库极大简化了创建多进程、多线程的代码工作,常用的调用方式如下:
并发执行不同的函数例子
from concurrent import futures
import time
def test1(num):
time.sleep(2)
return time.ctime(),num
def test2(num):
time.sleep(2)
return time.ctime(),num
with futures.ProcessPoolExecutor() as executor:
future1 = executor.submit(test1,1)
future2 = executor.submit(test2,2)
print(future1.result())
print(future2.result())
并发执行同一个函数,只是传参不一样
from concurrent import futures
import pendulum
import time
def test(task_num):
time.sleep(1)
return pendulum.now().to_datetime_string(), task_num
task_num = range(400)
with futures.ProcessPoolExecutor() as executor:
for future in executor.map(test, task_num, timeout=10):
pass
那假如要并发执行某个函数的参数很多,不想每次调用都写全所有的参数,只想通过关键词传某些参数呢?
这个网上已经有回答了,譬如How to use executor.map function in python on keyword arguments - Stack Overflow
def func(site, search_term, pages):
...
from functools import partial
from itertools import repeat
executor.map(func, zip(sites, repeat(search_term), repeat(pages)))
原理是通过 repeat 函数将本来无需传入的参构造个默认值
还有这个python - How to pass keyword argument to function called by concurrent.futures map call - Stack Overflow
res = executor.map(lambda x,y:spam(x,params=y), urls, params)
给要调用的函数用匿名函数 lambda 再封装一层
这个 2 个方法都用了executor.map(),是个函数式编程的函数,《流畅的 Python》里曾讲过 map大部分情况下都能被推导式代替,我想了个方法如下:
from concurrent import futures
import pendulum
import time
def test(task_num=0, name='test', n=0):
time.sleep(1)
return pendulum.now().to_datetime_string(), task_num, name, n
a = ['jack', 'Tom']
b = [9, 8]
with futures.ProcessPoolExecutor() as executor:
future_to_stuff = [executor.submit(test, name=name, n=n)
for name, n in zip(a, b)]
for future in future_to_stuff:
print(future.result())
上面的代码只用了 concurrent.futures的executor.submit,每个不同的关键词传参就调用一次executor.submit,通过列表推导式将多个调用聚集起来,最后再遍历这个列表推导式就行了。