简体   繁体   English

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

[英]How to get a return value from a thread, asynchonously?

My problem : starting a threaded function and, asynchronously , act upon the returned value我的问题:启动一个线程 function 并异步地对返回的值进行操作

I know how to:我知道如何:

  • start a threaded function with threading .threading启动一个带螺纹的 function 。 The problem: no simple way to get the result back问题:没有简单的方法可以返回结果
  • get the return value from a threaded function.从线程 function 获取返回值 The problem: it is synchronous问题:它是同步的

What I would like to achieve is similar to JavaScript's我想要实现的类似于 JavaScript 的

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

In pseudo-Python, I would think about something like (modifying the example from the answer to the linked thread)在伪 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

I want to stay if possible with threads (which do things at their own pace and I do not care when they are done), rather than asyncio (where I have to explicitly await things in a single thread)如果可能的话,我想保留线程(它们按照自己的节奏做事,我不在乎它们什么时候完成),而不是asyncio (我必须在单个线程中明确地await事情)

You can use add_done_callback of concurrent.futures library, so you can modify your example like this:您可以使用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)

You can use concurrent.futures.dd_done_callback as shown below.您可以使用concurrent.futures.dd_done_callback ,如下所示。 The callback must be a callable taking a single argument, the Future instance — and it must get the result from that as shown.回调必须是一个可调用的,采用单个参数,即Future实例——它必须从中获取结果,如图所示。 The example also adds some additional information to it which the callback function uses for printing its messages.该示例还向其中添加了一些附加信息,回调 function 用于打印其消息。

Note that the callback function(s) will be called concurrently, so the usual mutex precautions should be taken if there are shared resources involved.请注意,回调函数将被同时调用,因此如果涉及共享资源,则应采取通常的互斥预防措施。 This wasn't been done in the example, so sometimes the printed output will be jumbled.示例中没有这样做,因此有时打印的 output 会混乱。

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

Sample output:样品 output:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM