[Twisted-Python] xmlrpc - Possable failure to understand async concept

Drew Smathers drew.smathers at gmail.com
Fri Apr 24 13:33:08 MDT 2009


On Fri, Apr 24, 2009 at 2:28 AM, Nathan <nathan.stocks at gmail.com> wrote:
> On Thu, Apr 23, 2009 at 9:34 PM, Tim Allen <tim at commsecure.com.au> wrote:
>> Tim Hughes <thughes at thegoldfish.org> wrote:
>>> Am I completly missing the point here or is there something incorrect with
>>> my code.
>>
>> Yes, it seems you have missed the point somewhere.
>>
>>>     def blocking_method(self, duration=5):
>>>         """block the instance for a specified duration"""
>>>         started = time.asctime()
>>>         time.sleep(duration)
>>>         data = "I started at %s and i slept %d seconds then woke at %s" %
>>> (started, duration, time.asctime())
>>>         return data
>>
>>>     def blocking_method_fixed(self, duration=5):
>>>         d = Deferred()
>>>         d.callback(self.blocking_method(duration))
>>>         return d
>>
>> Your blocking_method_fixed() wraps the result of blocking_method() in a
>> Deferred, but it doesn't actually do anything to prevent
>> blocking_method() from blocking. Deferreds have no magical ability to
>> prevent things from blocking on their own, they are just a tool you can
>> use to handle some of the control-flow issues that arise when writing
>> non-blocking code.
>>
>> For example, here's a method that does more or less what
>> blocking_method() does, but in a non-blocking manner:
>>
>>    def non_blocking_method(self, duration=5):
>>        started = time.asctime()
>>        d = Deferred()
>>        reactor.callLater(duration, d.callback, None)
>>
>>        def do_stuff_after_timeout(result):
>>            # Here, 'result' will contain the None we passed to
>>            # callLater
>>            data = "I started at %s and I slept %d seconds then woke " \
>>                   "at %s" % (started, duration, time.asctime())
>>            return data
>>        d.addCallback(do_stuff_after_timeout)
>>        return d
>>
>> See how the method does some initial preparation, then schedules a
>> callback to be run after the long-running operation has completed.
>>
>> If you have a long-running network call to do instead of a simple
>> sleep, there's probably a Twisted API or addon that will perform the
>> call and give you back a Deferred, rather than blocking until it has an
>> answer. If you're trying to use a third-party client library that
>> doesn't offer a non-blocking API, about the only thing you can do is
>> call that API in a thread, using the reactor.callInThread() method (but
>> note that Twisted is not thread-safe, so the thing you call in a thread
>> can't use any of Twisted's functionality except via
>> reactor.callFromThread())
>
> The above email makes a great FAQ item, IMO.  I know there's already
> docs covering this, but this issue comes up soooo many times (it took
> me a month to wrap my head around it initially) that it wouldn't hurt
> to hit the issue from many directions in many styles.
>

It is one of the FAQ items:

http://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#HowdoIuseDeferredstomakemyblockingcodenon-blocking

Apparently there's also been some stitchwork done to commemorate this.

-Drew




More information about the Twisted-Python mailing list