manuele
manuele

Reputation: 389

async execution using twisted matrix

I'm trying to developing a simple twisted matrix example with the aim to perform async execution of a function but the print seams to tell me the execution is in sync or in sequential order, where is my misunderstanding?

from twisted.internet.defer import inlineCallbacks, returnValue
import time, random

def _print_(x):
    print "BAR", x

@inlineCallbacks
def sqrt(x):
    time.sleep(random.random())
    r = yield x*2
    print "FOO", r
    returnValue(r)

if __name__=='__main__':

    for dd in map(sqrt, range(10)):
        dd.addCallback(_print_)

Upvotes: 2

Views: 330

Answers (1)

Jean-Paul Calderone
Jean-Paul Calderone

Reputation: 48315

Twisted does not turn blocking code into non-blocking code nor synchronous code into asynchronous code. It gives you tools for writing asynchronous code.

inlineCallbacks is essentially the same thing as Deferred but with a different API. It doesn't change the single-threaded, cooperative multi-tasking nature of Twisted.

The program you've posted sequentially calls sqrt on the integers in range(10). Each call to sqrt sleeps for a random amount of time and then computes a result. The computation all happens in a single thread and so only one thing can happen at a time. When the sleep is happening, nothing else is.

What you can do is use one of Twisted's helpers to replace the blocking time.sleep() call:

from twisted.internet.task import deferLater
from twisted.internet import reactor

@inlineCallbacks
def sqrt(x):
    yield deferLater(reactor, random.random(), lambda: None)
    r = yield x*2
    print "FOO", r
    returnValue(r)

Now sqrt does not block in a time.sleep() call. Instead, it gives up control to the reactor. deferLater(...) returns a Deferred that will be fired for you after the given delay with the result of the given function (in this case the function is irrelevant since you only want to sleep, but deferLater requires some function).

Combined with inlineCallbacks, this gives you a "sleep" without blocking the reactor thread. The reactor is free to find other events to process while time is passing until it is time for the deferLater(...) Deferred to fire. When that happens, execution can resume inside sqrt and the computation can proceed. Of course, note that the computation itself is still blocking. However, since it's a simple integer multiplication, it probably doesn't block for long enough to matter.

The deferLater solution is specific to time.sleep. If you have other forms of blocking, you may need to learn about other APIs which address them.

You may also want to read How do I add two integers together with Twisted?

Upvotes: 1

Related Questions