什么是“async_generator”以及它与 Python 3.6 中的“协程”有何不同?

Rob*_*xal 4 python asynchronous generator coroutine python-asyncio

yield from我怀疑这与 b/w &的差异有关await。然而,除了新对象被指定为 an 之外async_generator,我还不清楚它和 a 之间的差异的后果coroutine。(除了我在标题中提出的问题之外,我不知道还能如何问这个问题......)

import asyncio

async def async_generator_spits_out_letters():
    yield 'a'
    yield 'b'
    yield 'c'
    yield 'd'
    await asyncio.sleep(0)

async def coroutine_prints_messages():
    while True:
        print('hi')
        await asyncio.sleep(2)

def test_it():
    print(type(async_generator_spits_out_letters))
    print(type(coroutine_prints_messages))
    # This is how I choose to do newlines....it's easier for me to read. :[
    print(); print()

    print(type(async_generator_spits_out_letters()))
    print(type(coroutine_prints_messages()))
Run Code Online (Sandbox Code Playgroud)

这给出:

<class 'async_generator'>
<class 'coroutine'>


<class 'function'>
<class 'function'>
Run Code Online (Sandbox Code Playgroud)

我无法理解这一点......

Rob*_*xal 6

为了使生成 async_generator函数在事件循环中运行,其输出必须包装在coroutine.

这是为了防止async_generator将值直接生成到事件循环中。


import asyncio

# This produces an async_generator
async def xrange(numbers):
    for i in range(numbers):
        yield i
        await asyncio.sleep(0)

# This prevents an async_generator from yielding into the loop.
async def coroutine_wrapper(async_gen, args):
    try:
        print(tuple([i async for i in async_gen(args)]))
    except ValueError:
        print(tuple([(i, j) async for i, j in async_gen(args)]))
Run Code Online (Sandbox Code Playgroud)

仅像任务和 future 一样循环。

如果循环接收到整数或字符串或……任何不是future从其任务之一派生的东西,它将中断。

因此coroutines必须:

  • 产生futures (或 , 的子类future
  • 或者不将任何值传递回循环。

这是主函数():

def main():
    print('BEGIN LOOP:')
    print()
    loop = asyncio.get_event_loop()
    xrange_iterator_task = loop.create_task(coroutine_wrapper(xrange, 20))
    try:
        loop.run_until_complete(xrange_iterator_task)
    except KeyboardInterrupt:
        loop.stop()
    finally:
        loop.close()
    print()
    print('END LOOP')
    print(); print()
    print('type(xrange) == {}'.format(type(xrange)))
    print('type(xrange(20) == {}'.format(type(xrange(20))))
    print()
    print('type(coroutine_wrapper) == {}'.format(type(coroutine_wrapper)))
    print('type(coroutine_wrapper(xrange,20)) == {}'.format(type(coroutine_wrapper(xrange, 20))))
if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

这是输出:

BEGIN LOOP:

(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

END LOOP


type(xrange) == <class 'function'>
type(xrange(20)) == <class 'async_generator'>

type(coroutine_wrapper) == <class 'function'>
type(coroutine_wrapper(xrange,20)) == <class 'coroutine'>
Run Code Online (Sandbox Code Playgroud)