从 `call_soon` 回调函数执行协程

Execute coroutine from `call_soon` callback function

我有以下情况:

我将使用修改后的 Hello World with call_soon() 来演示这一点:

import asyncio

def hello_world(loop):
    print('Hello')
    # Call some coroutine.
    yield from asyncio.sleep(5, loop=loop)
    print('World')
    loop.stop()

loop = asyncio.get_event_loop()

# Schedule a call to hello_world()
loop.call_soon(hello_world, loop)

# Blocking call interrupted by loop.stop()
loop.run_forever()
loop.close()

当我 运行 执行此操作时,不会打印任何内容,程序也不会结束。

Ctrl+C

Traceback (most recent call last):
  File "../soon.py", line 15, in <module>
    loop.run_forever()
  File "/usr/lib/python3.4/asyncio/base_events.py", line 276, in run_forever
    self._run_once()
  File "/usr/lib/python3.4/asyncio/base_events.py", line 1136, in _run_once
    event_list = self._selector.select(timeout)
  File "/usr/lib/python3.4/selectors.py", line 432, in select
    fd_event_list = self._epoll.poll(timeout, max_ev)
KeyboardInterrupt

实际发生了什么,为什么?

有什么正确的方法吗?

您提到的示例演示了如何安排回调。

如果使用 yield from 语法,函数实际上是一个 coroutine 并且必须进行相应的修饰:

@asyncio.coroutine
def hello_world(loop):
    print('Hello')
    yield from asyncio.sleep(5, loop=loop)
    print('World')
    loop.stop()

然后您可以使用 ensure_future:

将协程安排为任务
loop = asyncio.get_event_loop()
coro = hello_world(loop)
asyncio.ensure_future(coro)
loop.run_forever()
loop.close()

或者等效地,使用 run_until_complete:

loop = asyncio.get_event_loop()
coro = hello_world(loop)
loop.run_until_complete(coro)

两周后,python 3.5 will officially be released and you'll be able to use the new async/await语法:

async def hello_world(loop):
    print('Hello')
    await asyncio.sleep(5, loop=loop)
    print('World')

编辑:有点难看,但没有什么能阻止你创建一个回调来安排你的协程:

loop = asyncio.get_event_loop()
coro = hello_world(loop)
callback = lambda: asyncio.ensure_future(coro)
loop.call_soon(callback)
loop.run_forever()
loop.close()

您可以使用 call_soon 使用以下语法调用协程:

loop.call_soon(asyncio.async, hello_world(loop))