什么是 'async_generator' 以及它与 Python 3.6 中的 'coroutine' 有何不同?

What is an 'async_generator' & how is it different from a 'coroutine' in Python 3.6?

我怀疑这与 b/w yield fromawait 的差异有关。 但是,除了新的 object 被指定为 async_generator 之外,我不清楚它与 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()))

这给出:

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


<class 'function'>
<class 'function'>

我搞不懂这个...

为了 an async_generator-producing function to 运行 在事件循环中,它的输出必须包裹在 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)]))

循环只喜欢任务和未来。

如果一个循环从它的一个任务中接收到一个整数或字符串或..任何不是从 future 派生的东西,它就会中断。

因此 coroutines 必须:

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

这是 main():

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()

这是输出:

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'>