综合了别人写的两篇文章
inlineCallback:总体流程
Python中的协程实现,大都是这个流程,比如,tornado.gen(务必阅读)。
inlineCallbacks只是一个确保返回生成器的异常处理,最终返回一个生成器:
处理嵌套的思路是:如果遇到内层是未完成的deferred,就将自己添加到内层deferred回调链的结尾
和处理嵌套Deferred的思路类似
def inlineCallbacks(f):
@wraps(f)
def unwindGenerator(*args, **kwargs):
gen = f(*args, **kwargs)
return _inlineCallbacks(None, gen, Deferred())
return unwindGenerator
inlineCallback代码简写,给出一个比较顺畅的流程,去除了failure判定,省略的地方用…代替
def _inlineCallbacks(result, g, deferred):
waiting = [True, # waiting for result?
None] # result
while 1:
try:
# 每次启动生成器,它yield的值可以是:
# 1.正常返回值:使用这个对象,继续启动生成器
# 2.Deffered对象:已完成:那么使用结果,继续启动生成器
# 未完成:那么给这个Deferred对象增加一个回调函数:当该Deferred对象完成时,使用其结果,继续启动生成器
# 3.Failure对象,那么则将Failure对象封装的异常,传递给生成器
#(不仅可以在生成器外部使用send()方法向其传值,还可以使用throw()方法向其传递异常)
# 注意:当一个异步操作出现异常时,twisted会将异常信息封装进一个Failure对象
# 简而言之就是:第一次是使用None启动生成器,之后每次都是使用上一次的结果启动生成器
isFailure = isinstance(result, failure.Failure)
if isFailure:
result = result.throwExceptionIntoGenerator(g)
else:
result = g.send(result)
except StopIteration as e:
# 当生成器完成时,将deferred置为完成
deferred.callback(getattr(e, "value", None))
return deferred
except _DefGen_Return as e:
# 当通过returnValue()函数抛出_DefGen_Return异常时,那么从异常对象中提取值,并将其作为deferred的结果
...
deferred.callback(e.value)
return deferred
except:
# 启动生成器抛出其他异常时,将deferred置为失败
deferred.errback()
return deferred
# 下面是生成器返回Deferred对象时的情形
if _isinstance(result, Deferred):
def gotResult(r):
# 如果waiting[]为True,说明是result是个已经执行完毕的Deferred
# 然后gotResult()是在result.addBoth()中被调用执行的
# 那么通过waiting[1]保存结果,不进行递归,而是继续执行while循环
if waiting[0]:
waiting[0] = False
waiting[1] = r
else:
_inlineCallbacks(r, g, deferred)
# 当用addBoth添加result Deferred对象的事件回调时
# 如果该result是个已经执行完毕的Deferred,
# 那么在addBoth()函数内将直接执行事件回调函数gotResult(),并走gotResult()的if语句,然后又继续回到顶部
# 的while循环触发紧接着的下一个callback调用;
# 如果该result是个未执行完毕的Deferred,
# 那么添加该result的完成触发事件gotResult,
# 并执行result.addBoth()下面的if语句,将waiting[]修改为False,
# 然后return返回一个deferred,退出while循环。在接下来的时间中,
# 一旦该result对于的callback执行完毕,将触发该result添加的gotResult()回调,
# 并执行_inlineCallbacks(),然后继续执行callback链中的下一个callback调用。
# 如果内嵌deferred已经完成,那么会立刻激发gotResult()函数(addBoth会激发Deferred执行)
# gotResult()会将waiting[0]设置为False,waiting[1]保存result的结果,接下来会走 分支2;否则会走 分支1。
result.addBoth(gotResult) ##result是一个Deferred对象,所以有addBoth方法
# 分支1
if waiting[0]:
# 将waiting[0]置为False,当result完成时,会调用gotResult(),因为waiting[0]是False,所以会走其else分支,它会使用result的结果继续启动生成器
waiting[0] = False
return deferred
# 能执行到这里,说明是个已经执行完毕的Deferred(addBoth()中直接执行了gotResult()函数)
# 并将保存在waiting[1]中的结果保存到result中,然后回到顶部继续执行while循环
# 分支2
# result保存内层Deferred对象的结果
result = waiting[1]
# 重置状态,为下一轮while循环做准备
waiting[0] = True
waiting[1] = None
return deferred