twisted中DeferredList介绍
Deferredlist可以在列表中所有deferred对象就绪后执行指定回调函数,从本质上来说它返回了一个新的deferred对象。我们来看Deferredlist的初始化:
DeferredList(deferrlist, fireOnOneCallback=0, fireOnOneErrback=1, consumeErrors=1).addCallback(deferrlist_suc).addErrback(deferrlist_suc)
deferrlist: 其所需等待的defer对象列表
fireOnOneCallback:deferrlist列表中任一defer对象callback后,DeferredList就回调callback
fireOnOneErrback: deferrlist列表中任一defer对象errback后,如果deferr对象未指定errback,DeferredList就回调errback
consumeErrors:deferrlist列表中任一defer对象执行过程中发生错误后,如果deferr对象未指定errback, DeferredList就回调errback
下面是使用DeferredList一个简单例子,它定义了包括三个defer对象的DeferredList,每个defer对象定义了自己的回调函数并使用callback返回。运行该例子可以看到回调先执行defer_suc函数,然后以它的返回结果为参数执行defer_suc函数。 通过打印的结果可以看到deferrlist_suc 第一个参数result是一个二元元组列表, 列表中的每个元组对应于每个deferr的返回值,元组的第一项为True或False,用于说明返回是否为failure对象,第二项为对应的值。关于该元组项我们后面会进一步说明。大家可能注意到defer_suc和deferrlist_suc函数我都指定了suc标记,该标记是用于识别函数有callback还是errback进入,这样对一个defer对象可以使用同一个函数来处理callback和errback。
from twisted.internet.defer import Deferred, maybeDeferred, DeferredList from twisted.internet import defer from twisted.internet import reactor from twisted.python import failure import sys, os def defer_suc(result, suc): return result + ' defersuc' def deferrlist_suc(result, suc): print result deferrlist = [] for x in range(3): d = defer.Deferred() d.addCallback(defer_suc, True).addErrback(defer_suc, False) deferrlist.append(d) DeferredList(deferrlist, fireOnOneErrback=1, consumeErrors=1).addCallback(deferrlist_suc, True).addErrback(deferrlist_suc, False) for x in deferrlist: x.callback('a')
前面我们对每一个deferr都指定了其回调函数defer_suc,其实这个指定并不是必须的。在为deferr指定回调函数时,它的callback和errback由指定回调执行,否则所有信息都将直接进入到DeferredList的回调函数中。这里需要注意的是当fireOnOneErrback为真时如果deferr未指定errback回调,该deferr的errback都将会导致DeferredList的errback的执行;当fireOnOneErrback为假时,无论deferr是否指定了errback回调,Deferredlist都是由callback回调(不考虑consumeErrors)。下面的例子中 第一次deferrlist_suc的第二个参数为False,第二次为True, 分别表示由errback和callback返回。
for x in range(3): deferrlist.append(defer.Deferred()) DeferredList(deferrlist, fireOnOneErrback=1, consumeErrors=1).addCallback(deferrlist_suc, True).addErrback(deferrlist_suc, False) for x in deferrlist: x.errback('a') for x in range(3): deferrlist.append(defer.Deferred()) DeferredList(deferrlist, fireOnOneErrback=1, consumeErrors=1).addCallback(deferrlist_suc, True).addErrback(deferrlist_suc, False) for x in deferrlist: x.errback('a')
前面我们提到了deferrlist_suc中的result为一个二元元组列表, 元祖的第一项为True或False,用于说明返回是否为failure对象,第二项为对应的值。 那么在下面的例子中deferrlist_suc会输出什么呢?
def defer_suc(result, suc): return result def deferrlist_suc(result, suc): print result deferrlist = [] for x in range(3): d = defer.Deferred() d.addCallback(defer_suc, True).addErrback(defer_suc, False) deferrlist.append(d) DeferredList(deferrlist, consumeErrors=1).addCallback(deferrlist_suc, True).addErrback(deferrlist_suc, False) deferrlist[0].callback('a') deferrlist[1].errback('a') deferrlist[2].callback('a')
result中三个对象一模一样是否让你疑惑,为什么第二个deferr对象明明是errback,元祖第一项还是True呢。 因为deferr对象指定了errback回调函数,在errback发生时,
defer_suc函数就已经将错误吞掉,deferrlist_suc函数看到的都只是正常的返回而已,如果需要将err带入,即让元祖的第一项为False, 那么defer_suc函数返回的对象必须为一个failuer对象
def defer_suc(result, suc): return result if suc else failure.Failure(result, str)
最后一个问题:如果deferr的回调函数再加入deferrlist之后在指定会如何?根据文档描述,deferr指定的回调是否执行取决于其在回调前或后,如果在会掉前指定的话,该回调函数生效。但我测试时发现无论回调的指定在回调前或后,指定的回调函数都没有执行。 但无论如何请不要将deferr加入到deferrlist后为其指定回调函数,这将导致结果的