异步等待Python 3中的方法完成

时间:2019-08-02 09:14:06

标签: python concurrency python-asyncio

考虑以下简化示例:

def get_external_thing() -> str:
    my_variable = a_blocking_operation()
    my_variable.some_other_operation()
    return my_variable

externally_gathered_thing = None
while True:
    sleep(1)
    externally_gathered_thing = get_external_thing()
    if externally_gathered_thing:
        do_something_1()
        externally_gathered_thing = None
    do_something_2()

显然,这将进入循环,睡眠一秒钟,然后进入get_external_thing()并等待a_blocking_operation()完成。只要get_external_thing()正在运行,就什么都不会执行。

我要完成的工作是,如果get_external_thing()未完成,则强制循环继续,然后直接转到do_something_2()。但是,如果get_external_thing()完成并且externally_gathered_thing有一些值,我也希望执行do_something_1()

我怎么能完全用Python完成它?我试图用这个例子来学习异步,但是并没有产生任何可行的例子。由于项目要求,asyncio是首选,但不是必须的。

换句话说,无论do_something_2()的结果如何,我希望get_external_thing()每秒执行一次(或每秒+少量开销)。

注意:不要被while True构造所吓倒,它旨在在树莓派上连续运行:)

1 个答案:

答案 0 :(得分:1)

对于此类任务,请查看concurrent.futures模块。例如:

def get_external_thing() -> str:
    my_variable = a_blocking_operation()
    my_variable.some_other_operation()
    return my_variable

externally_gathered_thing = None
executor = concurrent.futures.ThreadPoolExecutor()
working = None

while True:
    if working is None:
        # if no work is in progress, start the external task in a bg thread
        working = executor.submit(get_external_thing)
    try:
        # wait for the external result, but no more than a second
        externally_gathered_thing = working.result(timeout=1)
        working = None
    except concurrent.futures.TimeoutError:
        # in case of timeout, proceed with our logic anyway, we'll get
        # back to waiting in the next iteration
        pass

    if externally_gathered_thing is not None:
        do_something_1()
        externally_gathered_thing = None
    do_something_2()

基于asyncio的解决方案是可能的,但是它仍然必须在后台使用线程来等待阻塞操作(run_in_executor的工作方式),因此它将asyncio的复杂性与线程。