1. 关于 future
在很多语言的并发编程中,你经常可以看到 future 的身影。future 的引入实际上是一种设计思想,它描述了一个替代 result 的对象,future 中的 result 通常是一开始未知,随着计算完成而变得已知。
在并发启动计算与获得最终计算结果之间存在一段空隙,future 在这个空隙间架了座桥。通常的处理这段空隙的方法是传递一个同步队列到每个worker,然后一旦workers结束,收集结果。但 future 使得这个过程更容易、更优雅。
2. 关于concurrent.futures
接口
concurrent.futures
提供了使用线程或进程工作池(pools of workers)来运行任务的接口。这个API使得多线程和多进程并发变得非常类似。它是在threading
和multiprocessing
接口上的封装。
Executors
被用来管理工作池;futures
被用来管理workers运行的结果。
首先创建Executor
的实例,然后submit任务来运行。当任务开始时,Future
的实例被返回。当任务结果被需要时,你能够使用Future
来阻塞直到获得结果。
3. 接口详解
(1)调度单个任务
executor调度单个任务,使用submit()
函数,然后用返回的Future
实例等待任务结果。
Code Example:
from concurrent import futures
import time
import random
def task(n):
time.sleep(random.randint(1, 10))
return n
executor = futures.ThreadPoolExecutor(max_workers=3)
future = executor.submit(task, 5)
print('future: {}'.format(future))
result = future.result()
print('result: {}'.format(result))
output:
future: <Future at 0x109c55210 state=running>
result: 5
(2)使用map()
调度多任务,有序返回
使用map()
,多个worker并发地从输入迭代器里取数据,处理,然后按顺序返回结果。
Code Example:
from concurrent import futures
import time
import random
def task(n):
time.sleep(random.randint(1, 10))
return n
executor = futures.ThreadPoolExecutor(max_workers=3)
results = executor.map(task, xrange(1, 10))
print('unprocessed results: {}'.format(results))
real_results = list(results)
print('real results: {}'.format(real_results))
output:
unprocessed results: <generator object result_iterator at 0x10fa19d70>
real results: [1, 2, 3, 4, 5, 6, 7, 8, 9]
(3)多任务调度,无序返回
不断将任务submit
到executor
,返回future
列表,使用as_completed
无序产生每个任务的结果。
Code Example:
from concurrent import futures
import random
import time
def task(n):
time.sleep(random.randint(1, 10))
return n
executor = futures.ThreadPoolExecutor(max_workers=3)
future_list = [executor.submit(task, i) for i in xrange(1, 10)]
for f in futures.as_completed(future_list):
print(f.result())
output:
1
4
2
3
7
6
5
8
9
Ref
Python - paralellizing CPU-bound tasks with concurrent.futures