如何异步地从线程中获取返回值



我的问题:启动一个线程函数,异步对返回值执行操作

我知道如何:

  • 使用threading启动一个线程函数。问题是:没有简单的方法可以得到结果
  • 从线程函数中获取返回值。问题是:它是同步的

我想要实现的类似于JavaScript的

aFunctionThatReturnsAPromise()
.then(r => {// do something with the returned value when it is available})
// the code here runs synchronously right after aFunctionThatReturnsAPromise is started

在伪Python中,我会考虑类似于(将示例从答案修改为链接线程(

import time
import concurrent.futures
def foo(bar):
print('hello {}'.format(bar))
time.sleep(10)
return 'foo'
def the_callback(something):
print(f"the thread returned {something}")
with concurrent.futures.ThreadPoolExecutor() as executor:
# submit the threaded call ...
future = executor.submit(foo, 'world!')
# ... and set a callback
future.callback(the_callback, future.result())  # ← this is the made up part
# or, all in one: future = executor.submit(foo, 'world!', callback=the_callback) # in which case the parameters probably would need to be passed the JS way
# the threaded call runs at its pace
# the following line is ran right after the call above
print("after submit")
# after some time (~10 seconds) the callback is finished (and has printed out what was passed to it)
# there should probably be some kind of join() so that the scripts waits until the thread is done

如果可能的话,我想留在线程(它们按照自己的节奏做事,我不在乎什么时候完成(,而不是asyncio(我必须在单个线程中显式地await(

您可以使用concurrent.futures.add_done_callback,如下所示。回调必须是接受单个参数Future实例的可调用函数,并且它必须从中获得结果,如图所示。该示例还添加了一些附加信息,回调函数使用这些信息来打印消息。

请注意,回调函数将被并发调用,因此如果涉及共享资源,则应采取通常的互斥预防措施。在下面的例子中,这不是,所以有时打印的输出会混乱不堪。

from concurrent import futures
import random
import time
def foo(bar, delay):
print(f'hello {bar} - {delay}')
time.sleep(delay)
return bar
def the_callback(fn):
if fn.cancelled():
print(f'args {fn.args}: canceled')
elif fn.done():
error = fn.exception()
if error:
print(f'args {fn.args}: caused error {error}')
else:
print(f'args {fn.args}: returned: {fn.result()}')
with futures.ThreadPoolExecutor(max_workers=2) as executor:
for name in ('foo', 'bar', 'bas'):
delay = random.randint(1, 5)
f = executor.submit(foo, name, delay)
f.args = name, delay
f.add_done_callback(the_callback)
print('fini')

样本输出:

hello foo - 5
hello bar - 3
args ('bar', 3): returned: bar
hello bas - 4
args ('foo', 5): returned: foo
args ('bas', 4): returned: bas
fini

您可以使用concurrent.futures库的add_done_callback,因此您可以这样修改您的示例:

def the_callback(something):
print(f"the thread returned {something.result()}")

with concurrent.futures.ThreadPoolExecutor() as executor:
future = executor.submit(foo, 'world!')
future.add_done_callback(the_callback)

最新更新