【问题标题】:How to get a return value from a thread, asynchonously?如何从线程异步获取返回值?
【发布时间】:2021-11-29 17:19:29
【问题描述】:

我的问题:启动一个线程函数并异步根据返回的值进行操作

我知道如何:

  • 使用threading 启动线程函数。问题:没有简单的方法可以返回结果
  • get the return value 来自线程函数。问题:它是同步的

我想要实现的和 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 事情)

【问题讨论】:

    标签: python python-3.x multithreading callback asynccallback


    【解决方案1】:

    您可以使用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
    

    【讨论】:

      【解决方案2】:

      您可以使用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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-09
        • 1970-01-01
        • 2018-04-09
        • 1970-01-01
        • 1970-01-01
        • 2018-06-30
        • 2011-10-17
        • 2018-04-15
        相关资源
        最近更新 更多