twisted之Deferred类的分析
@_oldStyle
class Deferred: called = False#类变量,在实例中引用时会自动在实例中生成
paused = False
_debugInfo = None
_suppressAlreadyCalled = False # Are we currently running a user-installed callback? Meant to prevent
# recursive running of callbacks when a reentrant call to add a callback is
# used.
_runningCallbacks = False # Keep this class attribute for now, for compatibility with code that
# sets it directly.
debug = False _chainedTo = None def __init__(self, canceller=None): self.callbacks = []#存放回调函数的,每个回调函数的参数是一样的
self._canceller = canceller
if self.debug:
self._debugInfo = DebugInfo()
self._debugInfo.creator = traceback.format_stack()[:-1] def addCallbacks(self, callback, errback=None,
callbackArgs=None, callbackKeywords=None,
errbackArgs=None, errbackKeywords=None):
"""
Add a pair of callbacks (success and error) to this L{Deferred}. These will be executed when the 'master' callback is run. @return: C{self}.
@rtype: a L{Deferred}
"""
assert callable(callback)
assert errback is None or callable(errback)
cbs = ((callback, callbackArgs, callbackKeywords),
(errback or (passthru), errbackArgs, errbackKeywords))
self.callbacks.append(cbs) if self.called:#如果已经回调了,就运行回调
self._runCallbacks()
return self def addCallback(self, callback, *args, **kw):
"""
Convenience method for adding just a callback. See L{addCallbacks}.
"""
return self.addCallbacks(callback, callbackArgs=args,
callbackKeywords=kw) def addErrback(self, errback, *args, **kw):
"""
Convenience method for adding just an errback. See L{addCallbacks}.
"""
return self.addCallbacks(passthru, errback,
errbackArgs=args,
errbackKeywords=kw) def addBoth(self, callback, *args, **kw):
"""
Convenience method for adding a single callable as both a callback
and an errback. See L{addCallbacks}.
"""
return self.addCallbacks(callback, callback,
callbackArgs=args, errbackArgs=args,
callbackKeywords=kw, errbackKeywords=kw) def addTimeout(self, timeout, clock, onTimeoutCancel=None): timedOut = [False] def timeItOut():
timedOut[0] = True
self.cancel() delayedCall = clock.callLater(timeout, timeItOut) def convertCancelled(value):
# if C{deferred} was timed out, call the translation function,
# if provdied, otherwise just use L{cancelledToTimedOutError}
if timedOut[0]:
toCall = onTimeoutCancel or _cancelledToTimedOutError
return toCall(value, timeout)
return value self.addBoth(convertCancelled) def cancelTimeout(result):
# stop the pending call to cancel the deferred if it's been fired
if delayedCall.active():
delayedCall.cancel()
return result self.addBoth(cancelTimeout)
return self def chainDeferred(self, d): d._chainedTo = self#把自己链接到d
return self.addCallbacks(d.callback, d.errback) def callback(self, result): assert not isinstance(result, Deferred)
self._startRunCallbacks(result) def errback(self, fail=None): if fail is None:
fail = failure.Failure(captureVars=self.debug)
elif not isinstance(fail, failure.Failure):
fail = failure.Failure(fail) self._startRunCallbacks(fail) def pause(self):#在runcallback时会判断paused是否为0,不为0的话会直接返回
"""
Stop processing on a L{Deferred} until L{unpause}() is called.
"""
self.paused = self.paused + 1 def unpause(self):
"""
Process all callbacks made since L{pause}() was called.
"""
self.paused = self.paused - 1
if self.paused:
return
if self.called:
self._runCallbacks() def cancel(self): if not self.called:
canceller = self._canceller
if canceller:
canceller(self)
else:
# Arrange to eat the callback that will eventually be fired
# since there was no real canceller.
self._suppressAlreadyCalled = True
if not self.called:
# There was no canceller, or the canceller didn't call
# callback or errback.
self.errback(failure.Failure(CancelledError()))
elif isinstance(self.result, Deferred):
# Waiting for another deferred -- cancel it instead.
self.result.cancel() def _startRunCallbacks(self, result):
if self.called:
if self._suppressAlreadyCalled:
self._suppressAlreadyCalled = False
return
if self.debug:
if self._debugInfo is None:
self._debugInfo = DebugInfo()
extra = "\n" + self._debugInfo._getDebugTracebacks()
raise AlreadyCalledError(extra)
raise AlreadyCalledError
if self.debug:
if self._debugInfo is None:
self._debugInfo = DebugInfo()
self._debugInfo.invoker = traceback.format_stack()[:-2]
self.called = True
self.result = result#为结果赋值
self._runCallbacks() def _continuation(self):#回调函数返回deferred时,放置一个标志callback。
"""
Build a tuple of callback and errback with L{_CONTINUE}.
"""
return ((_CONTINUE, (self,), None),
(_CONTINUE, (self,), None)) def _runCallbacks(self): if self._runningCallbacks:#如果正在运行回调,就返回
# Don't recursively run callbacks
return # Keep track of all the Deferreds encountered while propagating results
# up a chain. The way a Deferred gets onto this stack is by having
# added its _continuation() to the callbacks list of a second Deferred
# and then that second Deferred being fired. ie, if ever had _chainedTo
# set to something other than None, you might end up on this stack.
chain = [self]#chain队列 while chain:
current = chain[-1]#current为自己 if current.paused:
# This Deferred isn't going to produce a result at all. All the
# Deferreds up the chain waiting on it will just have to...
# wait.
return finished = True
current._chainedTo = None
while current.callbacks:
item = current.callbacks.pop(0)#从回调队列的第一开始调用,调用完后就从队列中remove
callback, args, kw = item[
isinstance(current.result, failure.Failure)]#根据result选择callback,还是errback
args = args or ()
kw = kw or {} # Avoid recursion if we can.
if callback is _CONTINUE:#说明该deferred对象有前级,要进入前级的调用
# Give the waiting Deferred our current result and then
# forget about that result ourselves.
chainee = args[0]
chainee.result = current.result
current.result = None
# Making sure to update _debugInfo
if current._debugInfo is not None:
current._debugInfo.failResult = None
chainee.paused -= 1#前级暂停数减1
chain.append(chainee)#退出当前callback循环
# Delay cleaning this Deferred and popping it from the chain
# until after we've dealt with chainee.
finished = False
break try:
current._runningCallbacks = True#在运行标志
try:
current.result = callback(current.result, *args, **kw)
if current.result is current:
warnAboutFunction(
callback,
"Callback returned the Deferred "
"it was attached to; this breaks the "
"callback chain and will raise an "
"exception in the future.")
finally:
current._runningCallbacks = False#取消在运行标志
except:
# Including full frame information in the Failure is quite
# expensive, so we avoid it unless self.debug is set.
current.result = failure.Failure(captureVars=self.debug)
else:
if isinstance(current.result, Deferred):#返回结果是deferred
# The result is another Deferred. If it has a result,
# we can take it and keep going.
resultResult = getattr(current.result, 'result', _NO_RESULT)
if resultResult is _NO_RESULT or isinstance(resultResult, Deferred) or current.result.paused:
# Nope, it didn't. Pause and chain.
current.pause()#要暂停当前defer
current._chainedTo = current.result
# Note: current.result has no result, so it's not
# running its callbacks right now. Therefore we can
# append to the callbacks list directly instead of
# using addCallbacks.
current.result.callbacks.append(current._continuation())#为结果回调
break
else:
# Yep, it did. Steal it.
current.result.result = None
# Make sure _debugInfo's failure state is updated.
if current.result._debugInfo is not None:
current.result._debugInfo.failResult = None
current.result = resultResult if finished:
# As much of the callback chain - perhaps all of it - as can be
# processed right now has been. The current Deferred is waiting on
# another Deferred or for more callbacks. Before finishing with it,
# make sure its _debugInfo is in the proper state.
if isinstance(current.result, failure.Failure):
# Stash the Failure in the _debugInfo for unhandled error
# reporting.
current.result.cleanFailure()
if current._debugInfo is None:
current._debugInfo = DebugInfo()
current._debugInfo.failResult = current.result
else:
# Clear out any Failure in the _debugInfo, since the result
# is no longer a Failure.
if current._debugInfo is not None:
current._debugInfo.failResult = None # This Deferred is done, pop it from the chain and move back up
# to the Deferred which supplied us with our result.
chain.pop()#完成一个defer的callback def __str__(self):
"""
Return a string representation of this C{Deferred}.
"""
cname = self.__class__.__name__
result = getattr(self, 'result', _NO_RESULT)
myID = id(self)
if self._chainedTo is not None:
result = ' waiting on Deferred at 0x%x' % (id(self._chainedTo),)
elif result is _NO_RESULT:
result = ''
else:
result = ' current result: %r' % (result,)
return "<%s at 0x%x%s>" % (cname, myID, result)
__repr__ = __str__ def __iter__(self):
return self def send(self, value=None):
if self.paused:
# If we're paused, we have no result to give
return self result = getattr(self, 'result', _NO_RESULT)
if result is _NO_RESULT:
return self
if isinstance(result, failure.Failure):
# Clear the failure on debugInfo so it doesn't raise "unhandled
# exception"
self._debugInfo.failResult = None
raise result.value
else:
raise StopIteration(result) # For PEP-492 support (async/await)
__await__ = __iter__
__next__ = send
def _inlineCallbacks(result, g, deferred):
"""
See L{inlineCallbacks}.
"""
# This function is complicated by the need to prevent unbounded recursion
# arising from repeatedly yielding immediately ready deferreds. This while
# loop and the waiting variable solve that by manually unfolding the
# recursion. waiting = [True, # waiting for result?
None] # result while 1:
try:
# Send the last result back as the result of the yield expression.
isFailure = isinstance(result, failure.Failure)
if isFailure:
result = result.throwExceptionIntoGenerator(g)
else:
result = g.send(result)
except StopIteration as e:
# fell off the end, or "return" statement
deferred.callback(getattr(e, "value", None))
return deferred
except _DefGen_Return as e:
# returnValue() was called; time to give a result to the original
# Deferred. First though, let's try to identify the potentially
# confusing situation which results when returnValue() is
# accidentally invoked from a different function, one that wasn't
# decorated with @inlineCallbacks. # The traceback starts in this frame (the one for
# _inlineCallbacks); the next one down should be the application
# code.
appCodeTrace = exc_info()[2].tb_next
if isFailure:
# If we invoked this generator frame by throwing an exception
# into it, then throwExceptionIntoGenerator will consume an
# additional stack frame itself, so we need to skip that too.
appCodeTrace = appCodeTrace.tb_next
# Now that we've identified the frame being exited by the
# exception, let's figure out if returnValue was called from it
# directly. returnValue itself consumes a stack frame, so the
# application code will have a tb_next, but it will *not* have a
# second tb_next.
if appCodeTrace.tb_next.tb_next:
# If returnValue was invoked non-local to the frame which it is
# exiting, identify the frame that ultimately invoked
# returnValue so that we can warn the user, as this behavior is
# confusing.
ultimateTrace = appCodeTrace
while ultimateTrace.tb_next.tb_next:
ultimateTrace = ultimateTrace.tb_next
filename = ultimateTrace.tb_frame.f_code.co_filename
lineno = ultimateTrace.tb_lineno
warnings.warn_explicit(
"returnValue() in %r causing %r to exit: "
"returnValue should only be invoked by functions decorated "
"with inlineCallbacks" % (
ultimateTrace.tb_frame.f_code.co_name,
appCodeTrace.tb_frame.f_code.co_name),
DeprecationWarning, filename, lineno)
deferred.callback(e.value)
return deferred
except:
deferred.errback()
return deferred if isinstance(result, Deferred):
# a deferred was yielded, get the result.
def gotResult(r):
if waiting[0]:
waiting[0] = False
waiting[1] = r
else:
_inlineCallbacks(r, g, deferred) result.addBoth(gotResult)
if waiting[0]:
# Haven't called back yet, set flag so that we get reinvoked
# and return from the loop
waiting[0] = False
return deferred result = waiting[1]
# Reset waiting to initial values for next loop. gotResult uses
# waiting, but this isn't a problem because gotResult is only
# executed once, and if it hasn't been executed yet, the return
# branch above would have been taken. waiting[0] = True
waiting[1] = None return deferred
twisted之Deferred类的分析的更多相关文章
- 移动web app开发必备 - Deferred 源码分析
		
姊妹篇 移动web app开发必备 - 异步队列 Deferred 在分析Deferred之前我觉得还是有必要把老套的设计模式给搬出来,便于理解源码! 观察者模式 观察者模式( 又叫发布者-订阅者模 ...
 - MapReduce剖析笔记之八: Map输出数据的处理类MapOutputBuffer分析
		
在上一节我们分析了Child子进程启动,处理Map.Reduce任务的主要过程,但对于一些细节没有分析,这一节主要对MapOutputBuffer这个关键类进行分析. MapOutputBuffer顾 ...
 - 【建模】UML类关系分析
		
一.UML类关系分析 1.关联(asociation) 一般是一方拥有另一方对象的指针.箭头的方向是访问方向. 2.聚合(Aggregation)和组合(Composition) 聚合和关联一般不做区 ...
 - 使用AES加密的勒索类软件分析报告
		
报告名称: 某勒索类软件分析报告 作者: 李东 报告更新日期: 样本发现日期: 样本类型: 样本文件大小/被感染文件变化长度: 样本文件MD5 校验值: da4ab5e31793 ...
 - String类原理分析及部分方法
		
//String类原理分析及部分方法 //http://www.cnblogs.com/vamei/archive/2013/04/08/3000914.html //http://www.cnblo ...
 - APK包与类更改分析
		
360APK包与类更改分析 1 题目要求 这是360的全球招募无线攻防中的第二题,题目要求如下: 1)请以重打包的形式将qihootest2.apk的程序包名改为 "com.qihoo.cr ...
 - jQuery.Deferred 源码分析
		
作者:禅楼望月(http://www.cnblogs.com/yaoyinglong ) 1 引子 观察者模式是我们日常开发中经常用的模式.这个模式由两个主要部分组成:发布者和观察者.通过观察者模式, ...
 - CAF(C++ actor framework)(序列化之复杂类,分析 还有自己不懂的细思恐极函数实现)(三)
		
这里应该是序列化的最后一篇.感觉自己写的不是很好,也一点点在学习.这次就不贴上代码了.代码在github上的announce5.cpp.代码简单,但是分析下去会有细思恐极的感觉! 先看一下几个函数是干 ...
 - Arrays类的分析及使用
		
1. Arrays类介绍 Arrays类是Java API中提供的类,在java.util包中,此类包含用来操作数组的各种方法,比如排序和搜索,在这个类中如果指定数组引用为null,则此类方法都会抛 ...
 
随机推荐
- SELinux杂谈
			
----------------------------- 文末有推荐参考文档列表--------------------------- SELinux(Security Enhanced Linux ...
 - RTB业务知识之1-原生广告
			
一.背景 Native Advertising (Native Ads), 又称为原生广告, 是2013全球媒体界爆红的关键词,从2012年年底,就有人开始提了这个名词,接着到处都可以看到这个名词,再 ...
 - HTTP之Cookie
			
cookie是什么 浏览器存储在本地电脑上的一小段文本文件,cookie的存在主要是为了解决http协议无状态的问题,例如通过cookie来判断用户的登录状态,是否是某一个用户等. cookie的结构 ...
 - IE10 下系统出现Unable to get property 'PageRequestManager' of undefined or null reference错误
			
在本地调试时没有任何问题,上传到测试服务器(win2003 framework 4.0)后打开网站出现Unable to get property 'PageRequestManager' of un ...
 - PAT 乙级 1020 月饼 (25) C++版
			
1020. 月饼 (25) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 月饼是中国人在中秋佳节时吃的一种传统食 ...
 - 服务网关zuul之六:Zuul高可用
			
我们实际使用Zuul的方式如上图,不同的客户端使用不同的负载将请求分发到后端的Zuul,Zuul在通过Eureka调用后端服务,最后对外输出.因此为了保证Zuul的高可用性,前端可以同时启动多个Zuu ...
 - CSDN也有我的博客啦
			
我的CSDN:https://blog.csdn.net/qq_40875849
 - [转][Oracle]常见报错及处理
			
IIS 在安装 Oracle Client 后,需要命令行执行: iisreset 1.ORA-00257 参考自:https://jingyan.baidu.com/article/f71d6037 ...
 - js时间加减
			
1.选择上一周方法(不算当天) $("#weekSel").click(function () { //当前时间 var now = new Date(); //当前时间往前推一周 ...
 - c#day03
			
c#中的随机数 Random random = new Random(); //随机1~200之间的一个数 random.Next(,); //怪兽:防御为10,血量为10 //玩家:随机8~12的攻 ...