`concurrent.futures` 中 `with` 的函数

function of `with` in `concurrent.futures`

下面的代码按预期执行,返回的总完成时间几乎为零,因为它不等待线程完成每个作业。

import concurrent.futures
import time

start = time.perf_counter()


def do_something(seconds):
    print(f'Sleeping {seconds} second(s)...')
    time.sleep(seconds)
    return f'Done Sleeping...{seconds}'



executor= concurrent.futures.ThreadPoolExecutor()
secs = [10, 4, 3, 2, 1]

fs = [executor.submit(do_something, sec) for sec in secs]


finish = time.perf_counter()

print(f'Finished in {round(finish-start, 2)} second(s)')

但是使用 with 命令它会等待:

with concurrent.futures.ThreadPoolExecutor() as executor:
    secs = [10, 4, 3, 2, 1]

    fs = [executor.submit(do_something, sec) for sec in secs]

为什么? with 对多线程有这种行为的原因是什么?

concurrent.futures 没有很好的记录。当你创建一个执行器时,它必须被关闭以终止它的线程或进程。该代码将通过向线程推送 None 命令来通知线程退出,然后等待它们完成。在您的第一种情况下,如果您添加 executor.shutdown() 您会看到延迟。无论如何它都在那里 - 程序仍然需要 10 秒才能退出。

执行器可以用作上下文管理器(它作为 __enter____exit__ 方法)。当它退出 "with" 块时,将调用 __exit__ 并依次调用 shutdown

with statement中使用concurrent.futures.Executor相当于在使用后调用Executor.shutdown——导致执行器等待所有任务完成。 with 中使用的 Executor 保证正确关闭并发任务,即使在 with 块内发生错误也是如此。

Executor.shutdown(wait=True)

Signal the executor that it should free any resources that it is using when the currently pending futures are done executing. Calls to Executor.submit() and Executor.map() made after shutdown will raise RuntimeError.

[...]

You can avoid having to call this method explicitly if you use the with statement, which will shutdown the Executor (waiting as if Executor.shutdown() were called with wait set to True): [...]