1

我最近在学习 Twisted,刚才我重新阅读了一些关于 Deferred 的基本文档,这里有一些示例代码来自:http ://twistedmatrix.com/documents/12.3.0/core/howto/defer.html

注释掉第二g = Getter()个呢?会不会有重入问题?您对如何避免此类问题有一些好主意吗?

from twisted.internet import reactor, defer

class Getter:
    def gotResults(self, x):
        """
        The Deferred mechanism provides a mechanism to signal error
        conditions.  In this case, odd numbers are bad.

        This function demonstrates a more complex way of starting
        the callback chain by checking for expected results and
        choosing whether to fire the callback or errback chain
        """
        if self.d is None:
            print "Nowhere to put results"
            return

        d = self.d
        self.d = None
        if x % 2 == 0:
            d.callback(x*3)
        else:
            d.errback(ValueError("You used an odd number!"))

    def _toHTML(self, r):
        """
        This function converts r to HTML.

        It is added to the callback chain by getDummyData in
        order to demonstrate how a callback passes its own result
        to the next callback
        """
        return "Result: %s" % r

    def getDummyData(self, x):
        """
        The Deferred mechanism allows for chained callbacks.
        In this example, the output of gotResults is first
        passed through _toHTML on its way to printData.

        Again this function is a dummy, simulating a delayed result
        using callLater, rather than using a real asynchronous
        setup.
        """
        self.d = defer.Deferred()
        # simulate a delayed result by asking the reactor to schedule
        # gotResults in 2 seconds time
        reactor.callLater(2, self.gotResults, x)
        self.d.addCallback(self._toHTML)
        return self.d

def printData(d):
    print d

def printError(failure):
    import sys
    sys.stderr.write(str(failure))

# this series of callbacks and errbacks will print an error message
g = Getter()
d = g.getDummyData(3)
d.addCallback(printData)
d.addErrback(printError)

# this series of callbacks and errbacks will print "Result: 12"
#g = Getter() #<= What about commenting this line out? 
d = g.getDummyData(4)
d.addCallback(printData)
d.addErrback(printError)

reactor.callLater(4, reactor.stop)
reactor.run()
4

1 回答 1

1

是的,如果您评论第二个g = Getter(),您将遇到问题。同样Deferred会触发两次,因为您已将其Deferred存储在Getter对象中。特别是,第二次调用getDummyData将覆盖第一个Deferred.

你不应该这样做。一般来说,我不认为抓住Deferred物体是一个好主意,因为它们只能发射一次,而且很容易像你这样出现问题。

你应该做的是:

def getDummyData(self, x):
    ...
    d = defer.Deferred()
    # simulate a delayed result by asking the reactor to schedule
    # gotResults in 2 seconds time
    reactor.callLater(2, self.gotResults, x, d)
    d.addCallback(self._toHTML)
    return d

和:

def gotResults(self, x, d):
    """
    The Deferred mechanism provides a mechanism to signal error
    conditions.  In this case, odd numbers are bad.

    This function demonstrates a more complex way of starting
    the callback chain by checking for expected results and
    choosing whether to fire the callback or errback chain
    """
    if d is None:
        print "Nowhere to put results"
        return

    if x % 2 == 0:
        d.callback(x*3)
    else:
        d.errback(ValueError("You used an odd number!"))

请注意,在这种情况下Getter没有状态,这很好,并且您不需要为它使用类!

我的观点是Deferreds 应该用于让函数的调用者能够在结果可用时对其进行处理。它们应该用于任何更高级的东西。所以,我一直有

def func():
    d = defer.Deferred()
    ...
    return d

Deferred如果调用者出于某种原因必须坚持下去,他们可能会,但我可以自由地func多次调用,而不必担心隐藏状态。

于 2013-10-22T21:49:36.083 回答