1.基于生成式构造带状态的函数
一个函数多次调用都从上次返回的地方重新开始,相当于给一个机会从函数执行的中间切出去,再切回来的时候从原来的地方重新开始,这样能避免那种需要在函数执行过程中保留过多上下文信息的问题。对于异步io,如果我们能保留函数上下文,在等待异步io返回的时候切出去,这样就不需要费力写回调链了,一切就像同步调用一样,await一下,返回之后继续。唯一的问题在于,异步io本身是有传染性的,为了最大程度利用io等待的时间,我们实际希望协程在异步io切出去之后,程序能继续调度其它task
2.sleep函数实现
@types.coroutine
def __sleep0():
"""Skip one event loop run cycle.
This is a private helper for 'asyncio.sleep()', used
when the 'delay' is set to 0. It uses a bare 'yield'
expression (which Task.__step knows how to handle)
instead of creating a Future object.
"""
yield
async def sleep(delay, result=None, *, loop=None):
"""Coroutine that completes after a given time (in seconds)."""
if delay <= 0:
await __sleep0()
return result
if loop is None:
loop = events.get_event_loop()
future = loop.create_future()
h = loop.call_later(delay,
futures._set_result_unless_cancelled,
future, result)
try:
return await future
finally:
h.cancel()
这个地方是个很好的例子,用Future类封装事件等待,避免关心套接字相关的细节,但也意味着,我们如果希望将原有的io操作变成异步型的话,要么封装自己的协程,像sleep这样,将程序变成loop.run_until_complete,要么就是程序库自己提供了兼容asyncio的接口。
网友评论