async/await是什么?

14
我在努力理解Python中的async/await。
我的理解是否正确?
  • async@coroutine函数返回协程/生成器,而不是返回值。
  • await提取协程/生成器的实际返回值。
  • async函数的结果(协程)旨在添加到事件循环中。
  • await创建了事件循环和等待协程之间的“桥梁”(使下一点成为可能)。
  • @coroutineyield直接与事件循环通信(跳过直接调用者以等待结果)。
  • await只能在异步函数内部使用。
  • yield只能在@coroutine内使用。
@coroutine=@types.coroutine
2个回答

16

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

从技术上讲,types.coroutine 返回的是基于生成器的协程,与生成器和协程不同。

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

await(类似于 yield from)挂起协程的执行,直到它等待的可等待对象完成并返回结果。

async 函数的结果(协程)意味着要添加到事件循环中。

是的。

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

await 创建了一个挂起点,告诉事件循环将会发生某些 I/O 操作,从而允许其切换到另一个任务。

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

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

await 只能在 async 函数中使用。

是的。

yield 只能在协程中使用。

yield from 可以在基于生成器的协程(用 types.coroutine 装饰的生成器)中使用,自 Python 3.6 开始也可以在结果为异步生成器的 async 函数中使用。


1
我进行了进一步的调查。在回答 https://dev59.com/kVYO5IYBdhLWcg3wF93K#46462604 中,当 inner_coro 执行 yield 操作时,控制流程会直接跳转到事件循环(Event Loop),而不会返回给最初的调用者 outer_async。鉴于这个例子,你是否同意 yield 是协程与事件循环直接通信的方式? - industryworker3595112

0

演示代码:

(展示了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

8
这太复杂了。 - tushortz
这段代码展示的是:yield会生成结果并将协程挂起到send方法,但是await不会,注意到有两个连续的await函数运行。``` - logan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接