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,则此类方法都会抛 ...
随机推荐
- Git忽略规则和.gitignore规则不生效的解决办法
Git忽略规则和.gitignore规则不生效的解决办法 Git忽略规则: 在git中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .gitignore 文件的方法(如果 ...
- PAT 甲级 1006 Sign In and Sign Out (25)(25 分)
1006 Sign In and Sign Out (25)(25 分) At the beginning of every day, the first person who signs in th ...
- 将 GitHub 的某人的特定仓库复制到自己的账户下 的方法
访问仓库页面,点击 Fork 按钮创建自己的仓库 Fork 就是将 GitHub 的某个特定仓库复制到自己的账户下. Fork 出的仓库与原仓库是两个不同的仓库,开发者可以随意编辑. 新建的仓库名为& ...
- MySQL锁之三:MySQL的共享锁与排它锁编码演示
一.行锁之MySQL 使用SELECT ... FOR UPDATE 做事务写入前的确认 以MySQL 的InnoDB 为例,预设的Tansaction isolation level 为REPEA ...
- python programming作业5
# -*- coding: utf-8 -*- class ageError(Exception): pass class salaryError(Exception): pass class s ...
- VC中function函数解析
C++标准库是日常应用中非常重要的库,我们会用到C++标准库的很多组件,C++标准库的作用,不单单是一种可以很方便使用的组件,也是我们学习很多实现技巧的重要宝库.我一直对C++很多组件的实现拥有比较强 ...
- 大数据:Parquet文件存储格式【转】
一.Parquet的组成 Parquet仅仅是一种存储格式,它是语言.平台无关的,并且不需要和任何一种数据处理框架绑定,目前能够和Parquet适配的组件包括下面这些,可以看出基本上通常使用的查询引擎 ...
- 00002 - echo命令详解
用于字符串的输出 格式 echo string 使用echo实现更复杂的输出格式控制 1.显示普通字符串: echo "It is a test" 这里的双引号完全可以省略,以下命 ...
- AnimDynamics简介
转自:http://www.cnblogs.com/corgi/p/5405452.html AnimDynamics简介 AnimDynamics是UE4.11 Preview 5测试版本发布的An ...
- hue中使用oozie的workflow执行mr
workflow创建任务 进入hue–Workflows–编辑器–workflow–创建 拖一个mapreduce作业(在页面靠近顶端有一排选项图标)到页面中间虚线框中 Jar路径必须是hdfs中ja ...