微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决如何从线程异步获取返回值?

我的问题:启动一个线程函数,并异步对返回的值采取行动

我知道如何:

我想要实现的类似于 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 中,我会考虑类似的事情(将示例从 the answer 修改链接线程)

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,因此您可以像这样修改您的示例:

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)
,

您可以使用 concurrent.futures.dd_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 {erro}')
        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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。