twisted.internet.defer.inlineCallbacks
装饰器是用于 同步【异步操作】 的。它用于装饰生成器函数。调用该装饰器装饰的生成器函数会返回一个Deferred对象。其大致执行流程如下:
Python中的协程实现,大都是这个流程,比如,tornado.gen(务必阅读)。
#coding: utf8 from twisted.internet import reactor, defer d1 = defer.Deferred() d2 = defer.Deferred() def print_and_stop(result): print result reactor.stop() @defer.inlineCallbacks def func(): # 当yield的时候,d1尚未完成 r1 = yield d1 # 当yield的时候,d2已经完成 d2.callback(11) r2 = yield d2 # 通过returnValue返回值 defer.returnValue(r1 + r2) # 调用inlineCallbacks装饰的生成器函数,会返回一个defer d = func() d.addBoth(print_and_stop) reactor.callLater(1, d1.callback, 10) reactor.run()
def inlineCallbacks(f): @wraps(f) def unwindGenerator(*args, **kwargs): # 调用被装饰的函数,要求其必须返回一个生成器对象,否则抛出异常 try: gen = f(*args, **kwargs) except _DefGen_Return: raise TypeError( "inlineCallbacks requires %r to produce a generator; instead" "caught returnValue being used in a non-generator" % (f,)) if not isinstance(gen, types.GeneratorType): raise TypeError( "inlineCallbacks requires %r to produce a generator; " "instead got %r" % (f, gen)) # _inlineCallbacks是一个调度器 return _inlineCallbacks(None, gen, Deferred()) return unwindGenerator def _inlineCallbacks(result, g, deferred): waiting = [True, # waiting for result? None] # result while 1: try: # 每次启动生成器,它yield的值可以是: # 1,非Deferred对象且非Failure对象,那么使用这个对象,继续启动生成器 # 2,已完成的Deffered对象,那么使用这个Deferred对象的结果,继续启动生成器 # 3,未完成的Deferred对象,那么给这个Deferred对象增加一个回调函数:当该Deferred对象完成时,使用其结果,继续启动生成器 # 4,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): if waiting[0]: waiting[0] = False waiting[1] = r else: _inlineCallbacks(r, g, deferred) # 如果result已经完成,那么会立刻调用gotResult()函数, # gotResult()会将waiting[0]设置为False,waiting[1]保存result的结果,接下来会走 分支2;否则会走 分支1。 result.addBoth(gotResult) # 分支1 if waiting[0]: # 将waiting[0]置为False,当result完成时,会调用gotResult(),因为waiting[0]是False,所以会走其else分支,它会使用result的结果继续启动生成器 waiting[0] = False return deferred # 分支2 # result保存Deferred对象的结果,并重置状态,然后继续下一次循环 result = waiting[1] waiting[0] = True waiting[1] = None return deferred
是不是tornado的代码更好一点~~~