stop a twisted reactor after a gatherResults has finished

你。 提交于 2019-12-08 05:53:53

问题


new to twisted and just trying some deferred stuff out. I have the following code that makes up a list of 100 deferred calls - each waiting a random time and returning a value. That list the prints the results and finally terminates the reactor.

However, I'm pretty sure the way I'm stopping the reactor is probably... not great.

__author__ = 'Charlie'

from twisted.internet import defer, reactor
import random

def getDummyData(x):
    """returns a deferred object that will have a value in some random seconds
    sets up a callLater on the reactor to trgger the callback of d"""
    d = defer.Deferred()
    pause = random.randint(1,10)
    reactor.callLater(pause, d.callback, (x, pause))
    return d


def printData(result):
    """prints whatever is passed to it"""
    print result


def main():
    """makes a collection of deffered calls and then fires them. Stops reactor at end"""
    deferred_calls = [getDummyData(r) for r in range(0,100)]
    d = defer.gatherResults(deferred_calls, consumeErrors = True)
    d.addCallback(printData)

    # this additional callback on d stops the reacor
    # it fires after all the delayed callbacks have printed their values
    # the lambda ignored: ractor.stop() is required as callback takes a function
    # that takes a parameter.
    d.addCallback(lambda ignored: reactor.stop())

    # start the reactor.
    reactor.run()

if __name__ == "__main__":
    main()

I'm assuming that by adding a callback:

d.addCallback(lambda ignored: reactor.stop())

to the gathered results actually adds that callback on all the deferred items?

if so then there is probably a more elegant / correct way to do it?

Cheers!


回答1:


I'm assuming that by adding a callback: d.addCallback(lambda ignored: reactor.stop()) to the gathered results actually adds that callback on all the deferred items?

This isn't the case. gatherResults returns a new Deferred. It's just like any other Deferred you might come across. Its addCallback method does the same thing as usual: adds one function that will be called at one point in one callback chain.

The reason everything is nice and regular and unspecial like this is that gatherResults takes care of all the logic necessary to only give that regular Deferred that it returns a result after all of the input Deferreds have a result.

So, feel free to use gatherResults just like you're use any other Deferred-returning API. It's not special!

That said, starting with Twisted 12.3 there's a handy utility that you might want to use for this sort of thing - twisted.internet.task.react. Here's what your main function would look like if you used it:

def main(reactor):
    """makes a collection of deffered calls and then fires them. Stops reactor at end"""
    deferred_calls = [getDummyData(r) for r in range(0,100)]
    d = defer.gatherResults(deferred_calls, consumeErrors = True)
    d.addCallback(printData)
    return d

if __name__ == "__main__":
    from twisted.internet import task
    task.react(main, [])

And notice that you could change getDummyData so that it doesn't depend on the global reactor either:

def getDummyData(reactor, x):
    """returns a deferred object that will have a value in some random seconds
    sets up a callLater on the reactor to trgger the callback of d"""
    d = defer.Deferred()
    pause = random.randint(1,10)
    reactor.callLater(pause, d.callback, (x, pause))
    return d

def main(reactor):
    """makes a collection of deffered calls and then fires them. Stops reactor at end"""
    deferred_calls = [getDummyData(reactor, r) for r in range(0,100)]
    d = defer.gatherResults(deferred_calls, consumeErrors = True)
    d.addCallback(printData)
    return d

And now your code does't need any twisted.internet.reactor imports at all.

You could also use twisted.internet.task.deferLater in getDummyData to save a bit more typing:

def getDummyData(reactor, x):
    """returns a deferred object that will have a value in some random seconds
    sets up a callLater on the reactor to trgger the callback of d"""
    pause = random.randint(1,10)
    return deferLater(reactor, pause, lambda: (x, pause))


来源:https://stackoverflow.com/questions/19816613/stop-a-twisted-reactor-after-a-gatherresults-has-finished

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!