Event Loop
loop除了处理协程间的切换与结束时的异常捕捉,还要监听socket和文件描述符。先做个小测试:
>>> import asyncio
>>> loop = asyncio.get_event_loop()
>>> loop2 = asyncio.get_event_loop()
>>> loop is loop2
True # 两个loop实例是完全相同的
这意味着在一个coroutine内部获取loop,也可以通过asyncio.get_event_loop()
来得到,并不需要将loop作为参数传递给协程函数。对于框架设计者来说情况又不同了,最好在函数设计中接受一个loop参数,以防止用户使用loop策略来做一些额外的事情。
注意
get_event_loop()
方法仅在同样的线程中生效,如果在一个新线程中,应该用new_event_loop()
来获取新的loop,并通过set_event_loop(loop)
来将其设为该线程下的loop。
如果在一个coroutine函数中创建tasks而不await它们,会发生什么?事实上它们将独立于这个coroutine函数内的执行上下文来运行,这个coroutine函数将会在它启动的任务完成之前退出。
async def f():
loop = asyncio.get_event_loop()
for i in range(5):
loop.create_task(<coro>)
像上述情况,有时会在代码中看到loop变量,然后create_task()
才能被调用,另一种解决方案是使用asyncio.ensure_future()
方法,这个方法不需要通过loop来调用。
async def f():
for i in range(5):
asyncio.ensure_future(<coro>)
或可以通过辅助函数来做到。
def create_task(coro):
return asyncio.get_event_loop().create_task(coro)
async def f():
for i in range(5):
create_task(<coro>)
loop.create_task()
和asyncio.ensure_future()
对初学者来说是很微妙和困惑的,下一章讨论其中的差异。