一次运行一个任务:
from concurrent.futures import ThreadPoolExecutor
def foo(a, b):
print(a)
print(b)
# executor = ThreadPoolExecutor(max_workers=1)
# executor.submit(foo)
# executor.shutdown()
with ThreadPoolExecutor(max_workers=1) as executor:
executor.submit(foo, 'foo', 'bar')
这里用了with语句,当然你也可以选择不用with,就是注释掉的代码,你需要手动关闭线程池.
这里说一下with语句,很多人都不了解其细节.
在进入with语句块的时候,会执行__entry__()函数,然后这个函数的返回值给as后面的那个变量, 当退出with语句块的时候,会执行__exit__()函数.
来看一下源代码:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.shutdown(wait=True)
return False
当你自己的class定义了__enter__和__exit__后,也就可以安心的使用with语句了.
一般来说,__enter__都是return self,而__exit__都是结束的时候你要做的事情.
用with语句的一个好处是,你不需要精力放在线程池的建立和关闭上, 你只需要关注你想要实现什么.
就像你写web,你不许要考虑con tent-type,这不应该是程序员应该考虑的,程序员更多的把精力放在业务上.
如果你想一次执行多个任务怎么办?
使用map函数.
import os
from concurrent.futures import ThreadPoolExecutor
def foo(a, b):
print(a)
print(b)
with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
executor.map(foo, (1, 2, 3), (3, 2, 3))
map函数的定义如下:
def map(self, fn, *_iterables, timeout=None, chunksize=1):
第一个参数是接受一个函数(函数名字,不要加后面的括号),第二个参数是一个可变参数,它需要一个多个迭代器.
因为,你的那个要执行任务的函数可能需要多个参数,那么迭代器的数量与参数的数量是一样的.
过去的时候,我不知道可以接受多个迭代器,所以用的模式匹配……
import os
from concurrent.futures import ThreadPoolExecutor
def foo(data):
a, b = data
print(a)
print(b)
iter1 = (1, 2, 3)
iter2 = (3, 2, 3)
with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
executor.map(foo, zip(iter1, iter2))
看上去好蠢.
注意看这行的代码: with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor
max_workers=os.cpu_count()
,这样做有什么好处呢?你的代码是可计算的,什么意思,你的电脑CPU是4核心,他的电脑是8核心CPU, 那么你的程序移植到他的电脑上去后,可以发挥最佳效果.
额外说点东西, 为什么 with语句会与__entry__和__exit__这两个函数有联系,这个叫协议.
举个例子, a == b
等价于 a.__eq__(b)
, 如果你是Clojure程序员会更清楚协议.
为了方便程序员,我们事先约定好了一系列的协议,Python会帮你实现这些协议,这一切都会让你的工作变得更轻松.