concurrent.futures

异步执行可以由 ThreadPoolExecutor 使用线程或由 ProcessPoolExecutor 使用单独的进程来实现。 两者都是实现抽像类 Executor 定义的接口。

concurrent.futures.Executor

抽象类提供异步执行调用方法。要通过它的子类调用,而不是直接调用!

  1. 调度某函数
submit(fn, /, *args, **kwargs)

调度可调用对象 fn,以 fn(*args **kwargs) 方式执行并返回 Future 对象代表可调用对象的执行。

  1. 一次性调度
map(func, *iterables, timeout=None, chunksize=1)

将可迭代对象中的每个元素,作为参数给 func,创建 len(iterables)个调度。

  1. 关闭执行器
shutdown(wait=True, *, cancel_futures=False)

等待所有 future 执行完毕,然后关闭执行器,可以使用 with 语句,避免直接调用 shutdown

with ThreadPoolExecutor(max_workers=4) as e:
    e.submit(...)

ThreadPoolExecutor

concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())

Executor 的一个子类,使用最多 max_workers 个线程的线程池来异步执行调用。

import concurrent.futures
import random
import time
from concurrent.futures import ThreadPoolExecutor


timeArr = [random.randint(1,5) for i in range(10)]  # 生成10个 1-10 的随机数字

def test(n):
    time.sleep(n)
    print(f"sleep {n}s")
    return n

with ThreadPoolExecutor(max_workers=5) as e:
    futs = [e.submit(test,n) for n in timeArr]  # 线程池执行器,执行线程
    for fut in concurrent.futures.as_completed(futs):  # as_conpleted可以处理 futures,并返回执行完毕的 future
        try:
            print(f"result is {fut.result()}")  # 打印 future 执行结果
        except Exception as exc:
            print(exc)

ProcessPoolExecutor

concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=())

异步地执行调用的 Executor 子类使用最多具有 max_workers 个进程的进程池

ThreadPoolExecutor类似。

Future 对象

Future 实例由 Executor.submit() 创建。

  • cancel()

    尝试取消调用。 如果调用正在执行或已结束运行不能被取消则该方法将返回 False,否则调用会被取消并且该方法将返回 True

  • cancelled()

    如果调用成功取消返回 True

  • running()

    如果调用正在执行而且不能被取消那么返回True

  • done()

    如果调用已被取消或正常结束那么返回 True

  • result(timeout=None)

    返回调用返回的值。如果调用还没完成那么这个方法将等待 timeout 秒。如果在 timeout 秒内没有执行完成,concurrent.futures.TimeoutError 将会被触发。timeout 可以是整数或浮点数。如果 timeout 没有指定或为 None,那么等待时间就没有限制。如果 futrue 在完成前被取消则 CancelledError 将被触发。如果调用引发了一个异常,这个方法也会引发同样的异常。

  • exception(timeout=None)

    返回由调用引发的异常。如果调用还没完成那么这个方法将等待 timeout 秒。如果在 timeout 秒内没有执行完成,concurrent.futures.TimeoutError 将会被触发。timeout 可以是整数或浮点数。如果 timeout 没有指定或为 None,那么等待时间就没有限制。如果 futrue 在完成前被取消则 CancelledError 将被触发。如果调用正常完成那么返回 None

  • add_done_callback(fn)

    附加可调用 fn 到 future 对象。当 future 对象被取消或完成运行时,将会调用 fn,而这个 future 对象将作为它唯一的参数。加入的可调用对象总被属于添加它们的进程中的线程按加入的顺序调用。如果可调用对象引发一个 Exception 子类,它会被记录下来并被忽略掉。如果可调用对象引发一个 BaseException 子类,这个行为没有定义。如果 future 对象已经完成或已取消,fn 会被立即调用。

concurrent.futures.as_completed(fs, timeout=None)

等待 fs 实例们执行,每个 future 实例执行完毕,都会返回 future。fs要是可迭代对象

import concurrent.futures
import time
from concurrent.futures import ThreadPoolExecutor


def test(n):
    time.sleep(n)
    print(f"sleep {n}s")
    return n

# 回调函数,必须要带一个可以接受 future 的参数
def cb(fut):
    print("Callback called.")

with ThreadPoolExecutor(max_workers=5) as e:
    fut = e.submit(test,2)
    fut.add_done_callback(cb)  # 添加回调
    print(fut.done())
    for fut in concurrent.futures.as_completed([fut]):  # 等待 fut 执行完毕
        print(fut.done())