【问题标题】:What does async/await do?异步/等待做什么?
【发布时间】:2017-09-22 11:42:06
【问题描述】:

我正在尝试在 python 中使用 async/await。

我走对了吗?

  • async@coroutine 函数返回协程/生成器,而不是返回值。
  • await提取协程/生成器的实际返回值。

  • async 函数结果(协程)旨在添加到事件循环中。

  • await 在事件循环和等待的协程之间创建“桥梁”(启用下一点)。
  • @coroutineyield 直接与事件循环通信。 (跳过等待结果的直接调用者)

  • await 只能在异步函数内部使用。

  • yield 只能在 @coroutine 内部使用。

(@coroutine = @types.coroutine)

【问题讨论】:

    标签: python python-3.x async-await


    【解决方案1】:

    async@coroutine 函数返回协程/生成器,而不是返回值

    从技术上讲,types.coroutine 返回一个基于生成器的协程,它不同于生成器,也不同于协程。

    await 提取协程/生成器的实际返回值。

    await,类似于yield from,暂停协程的执行,直到它所接受的等待完成并返回结果。

    异步函数结果(协程)被添加到事件循环中。

    是的。

    await 在事件循环和等待的协程之间创建“桥梁”(启用下一个点)。

    await 创建一个暂停点,向事件循环指示将发生一些 I/O 操作,从而允许它切换到另一个任务。

    @coroutine 的 yield 直接与事件循环通信。 (跳过等待结果的直接调用者)

    不,基于生成器的协程使用yield from 的方式与await 类似,而不是yield

    await 只能在异步函数中使用。

    是的。

    yield 只能在协程内部使用。

    yield from 可以在基于生成器的协程(用 types.coroutine 修饰的生成器)中使用,并且从 Python 3.6 开始,可以在导致异步生成器的 async 函数中使用。

    【讨论】:

    • 我进一步调查。在回答stackoverflow.com/a/46462604/3595112 时,当inner_coro 执行yield 时,控制流进入事件循环,跳过初始调用者outer_async。鉴于这个例子,你是否同意这里的yield 是协程直接与事件循环通信的一种方式?
    【解决方案2】:

    演示代码:

    (说明asynctypes.coroutine 和事件循环之间的整个控制流程)

    import types
    
    
    class EL:
        """Fake An event loop."""
    
        def __init__(self, outer_async):
            self.outer_async = outer_async
    
        def loop(self):
            print('    EL.loop : outer_async.send(None)')
            send_result = self.outer_async.send(None) # seed outer_async.
            print('    EL.loop : outer_async.send(None) -> outer_async_send_result = {}'.format(send_result))
    
            do_loop = True
            loop_counter = 0
    
            while do_loop:
                print()
                loop_counter += 1
                try:
                    arg = send_result + '-loop(send-{})'.format(loop_counter)
                    print('    EL.loop.while : task.outer_async.send({})'.format(arg))
                    send_result = self.outer_async.send(arg) # raises StopIteration.
                    print('    EL.loop.while : task.outer_async.send({}) -> send_result = {}'.format(arg, send_result))
                except StopIteration as e:
                    print('    EL.loop.while : except StopIteration -> {}'.format(e.value))
                    do_loop = False
            return loop_counter
    
    
    async def outer_async(label):
        inner_coro_arg = label + '-A1'
        print('        outer_async({}) : await inner_coro({})'.format(label, inner_coro_arg))
        await_result = await inner_coro(inner_coro_arg)
        print('        outer_async({}) : await inner_coro({}) -> await_result = {}'.format(label, inner_coro_arg, await_result))
    
        inner_coro_arg = label + '-A2'
        print('        outer_async({}) : await inner_coro({})'.format(label, inner_coro_arg))
        await_result = await inner_coro(inner_coro_arg)
        print('        outer_async({}) : await inner_coro({}) -> await_result = {}'.format(label, inner_coro_arg, await_result))
        return 555555
    
    
    @types.coroutine
    def inner_coro(inner_coro_label):
        yld_arg = inner_coro_label + '-C(yield)'
        print('            inner_coro({}) : yield({})'.format(inner_coro_label, yld_arg))
        yield_result = yield yld_arg
        print('            inner_coro({}) : yield({}) -> yield_result = {}'.format(inner_coro_label, yld_arg, yield_result))
        return_value = yield_result + '-C(return)'
        print('            inner_coro({}) : return -> {}'.format(inner_coro_label, return_value))
        return return_value
    
    
    def main():
        loop = EL(outer_async('$$'))
        print('main() : loop.loop')
        loop_outer_async = loop.loop()
        print('main() : loop.loop -> {}'.format(loop_outer_async))
    
    
    if __name__ == '__main__':
        main()
    

    结果:

    main() : loop.loop
        EL.loop : outer_async.send(None)
            outer_async($$) : await inner_coro($$-A1)
                inner_coro($$-A1) : yield($$-A1-C(yield))
        EL.loop : outer_async.send(None) -> outer_async_send_result = $$-A1-C(yield)
    
        EL.loop.while : task.outer_async.send($$-A1-C(yield)-loop(send-1))
                inner_coro($$-A1) : yield($$-A1-C(yield)) -> yield_result = $$-A1-C(yield)-loop(send-1)
                inner_coro($$-A1) : return -> $$-A1-C(yield)-loop(send-1)-C(return)
            outer_async($$) : await inner_coro($$-A1) -> await_result = $$-A1-C(yield)-loop(send-1)-C(return)
            outer_async($$) : await inner_coro($$-A2)
                inner_coro($$-A2) : yield($$-A2-C(yield))
        EL.loop.while : task.outer_async.send($$-A1-C(yield)-loop(send-1)) -> send_result = $$-A2-C(yield)
    
        EL.loop.while : task.outer_async.send($$-A2-C(yield)-loop(send-2))
                inner_coro($$-A2) : yield($$-A2-C(yield)) -> yield_result = $$-A2-C(yield)-loop(send-2)
                inner_coro($$-A2) : return -> $$-A2-C(yield)-loop(send-2)-C(return)
            outer_async($$) : await inner_coro($$-A2) -> await_result = $$-A2-C(yield)-loop(send-2)-C(return)
        EL.loop.while : except StopIteration -> 555555
    main() : loop.loop -> 2
    

    【讨论】:

    • 这太复杂了。
    • 这段代码说明了什么:yield 将生成结果并将协程 hangsend 方法,但是,await 不是,注意有两个 continue await 函数跑。 ```
    猜你喜欢
    • 1970-01-01
    • 2022-12-18
    • 2013-03-17
    • 2022-01-17
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2016-07-07
    • 2016-03-25
    相关资源
    最近更新 更多