@_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类的分析的更多相关文章

  1. 移动web app开发必备 - Deferred 源码分析

    姊妹篇  移动web app开发必备 - 异步队列 Deferred 在分析Deferred之前我觉得还是有必要把老套的设计模式给搬出来,便于理解源码! 观察者模式 观察者模式( 又叫发布者-订阅者模 ...

  2. MapReduce剖析笔记之八: Map输出数据的处理类MapOutputBuffer分析

    在上一节我们分析了Child子进程启动,处理Map.Reduce任务的主要过程,但对于一些细节没有分析,这一节主要对MapOutputBuffer这个关键类进行分析. MapOutputBuffer顾 ...

  3. 【建模】UML类关系分析

    一.UML类关系分析 1.关联(asociation) 一般是一方拥有另一方对象的指针.箭头的方向是访问方向. 2.聚合(Aggregation)和组合(Composition) 聚合和关联一般不做区 ...

  4. 使用AES加密的勒索类软件分析报告

    报告名称:  某勒索类软件分析报告    作者:        李东 报告更新日期: 样本发现日期: 样本类型: 样本文件大小/被感染文件变化长度: 样本文件MD5 校验值: da4ab5e31793 ...

  5. String类原理分析及部分方法

    //String类原理分析及部分方法 //http://www.cnblogs.com/vamei/archive/2013/04/08/3000914.html //http://www.cnblo ...

  6. APK包与类更改分析

    360APK包与类更改分析 1 题目要求 这是360的全球招募无线攻防中的第二题,题目要求如下: 1)请以重打包的形式将qihootest2.apk的程序包名改为 "com.qihoo.cr ...

  7. jQuery.Deferred 源码分析

    作者:禅楼望月(http://www.cnblogs.com/yaoyinglong ) 1 引子 观察者模式是我们日常开发中经常用的模式.这个模式由两个主要部分组成:发布者和观察者.通过观察者模式, ...

  8. CAF(C++ actor framework)(序列化之复杂类,分析 还有自己不懂的细思恐极函数实现)(三)

    这里应该是序列化的最后一篇.感觉自己写的不是很好,也一点点在学习.这次就不贴上代码了.代码在github上的announce5.cpp.代码简单,但是分析下去会有细思恐极的感觉! 先看一下几个函数是干 ...

  9. Arrays类的分析及使用

    1.  Arrays类介绍 Arrays类是Java API中提供的类,在java.util包中,此类包含用来操作数组的各种方法,比如排序和搜索,在这个类中如果指定数组引用为null,则此类方法都会抛 ...

随机推荐

  1. 黄聪:jquery+Datatables出现数据过长,表格不自动换行,columns设置width失效的办法

    添加下面的CSS代码即可: table.dataTable.nowrap th, table.dataTable.nowrap td{white-space: normal !important;}

  2. IDEA创建Springmvc项目

    项目主要步骤如下: 1.创建一个javaweb动态项目 2.导入springmvc demo所需要的jar包 3.生成项目war包 4.配置项目tomacat服务器 5.配置web.xml文件 6.编 ...

  3. LeetCode——5.Longest Palindromic Substring

    一.题目链接:https://leetcode.com/problems/longest-palindromic-substring/ 二.题目大意: 给定一个字符串,找出它最长的回文子串.例如,字符 ...

  4. JPanel添加键盘监听事件

    因为在自己的游戏需求中谢了要用键盘控制飞机的移动,所以用到键盘监听事件,但是使用了JPanel之后添加了键盘监听事件,按相应的方向键飞机并没有反应.但是如果是为JFrame的内容面板加则会有反应. 为 ...

  5. Javascript之类型转换(二)

    前言 类型转换js中主要有以下几种情况: 1.条件判断时: 2.对象转基本类型时: 3.四则运算时: 4.‘==’操作符比较值时: 5.比较运算符时. 一.条件判断时 在条件判断时,除了 undefi ...

  6. java1.8 新特性(五 如何使用filter,limit ,skip ,distinct map flatmap ,collect 操作 java集合)

    使用filter 根据 条件筛选 出结果:例如 找出 user 中 age >=15 的用户 package lambda.stream; /** * @author 作者:cb * @vers ...

  7. [转][CentOS]修改IP后立即生效

    来自:http://bbs.51cto.com/thread-789908-1.html Linux系统里修改IP地址后该如何使之即刻生效,有两种方法可以解决: (1) sudo ifdown eth ...

  8. [UE4]关卡蓝图

  9. SCCM 2012 R2实战系列之二:前提工作准备

    在上一篇中,我们完成了SQL Server 2012的安装和配置.现在跟大家分享SCCM安装前的准备工作. 2.1 SCCM 2012 R2 准备工作 2.1.1 创建并分配System Manage ...

  10. CRM 2016 执行IFrame 子页面中函数

    CRM代码: var iframe = Xrm.Page.getControl("IFRAME_xxx").getObject(); iframe.contentWindow.Re ...