Python并发第一个结果结束等待尚未完成的结果

Python concurrency first result ends waiting for not yet done results

我想做的是Move on...在第一个True之后,不关心还没有完成I/O绑定的任务。在下面的例子中,two() 是第一个也是唯一一个 True 所以程序需要像这样执行:

Second
Move on..

不是:

Second
First
Third
Move on...

import concurrent.futures
import time


def one():
    time.sleep(2)
    print('First')
    return False


def two():
    time.sleep(1)
    print('Second')
    return True


def three():
    time.sleep(4)
    print('Third')
    return False


tasks = [one, two, three]
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    for t in range(len(tasks)):
        executor.submit(tasks[t])

print('Move on...')

with 语句不是您想要的,因为它等待所有提交的作业完成。您需要提交任务,就像您已经做的那样,然后调用 as_completed 等待第一个 returns 为真(并且不再)的任务:

executor = concurrent.futures.ThreadPoolExecutor()
futures = [executor.submit(t) for t in tasks]
for f in concurrent.futures.as_completed(futures):
    if f.result():
        break
print('Move on...')

concurrent.futures.ThreadPoolExecutor 的问题是,一旦任务被提交,它们将 运行 完成,所以程序将打印 'Move on...' 但如果实际上没有别的事可做,程序不会终止,直到函数 onethree 终止并(并打印它们的消息)。所以程序保证运行至少4秒

最好使用 multiprocessing.pool 模块中的 ThreadPool class,它支持 terminate 方法,可以终止所有未完成的任务。最接近 as_completed 方法的可能是使用 imap_unordered 方法,但这需要一个辅助函数用于所有 3 个任务。但是我们可以使用 apply_async 指定在结果可用时调用的回调函数:

from multiprocessing.pool import ThreadPool
import time
from threading import Event

def one():
    time.sleep(2)
    print('First')
    return False


def two():
    time.sleep(1)
    print('Second')
    return True


def three():
    time.sleep(4)
    print('Third')
    return False

def my_callback(result):
    if result:
        executor.terminate() # kill all other tasks
        done_event.set()

tasks = [one, two, three]
executor = ThreadPool(3)
done_event = Event()
for t in tasks:
    executor.apply_async(t, callback=my_callback)
done_event.wait()
print("Moving on ...")