views:

1195

answers:

5

I was wondering if there's any library for asynchronous method calls in Python. It would be great if you could do something like

@async
def longComputation():
    <code>


token = longComputation()
token.registerCallback(callback_function)
# alternative, polling
while not token.finished():
    doSomethingElse()
    if token.finished():
        result = token.result()

Or to call a non-async routine asynchronously

def longComputation()
    <code>

token = asynccall(longComputation())

It would be great to have a more refined strategy as native in the language core. Was this considered?

+12  A: 

It's not in the language core, but a very mature library that does what you want is Twisted. It introduces the Deferred object, which you can attach callbacks or error handlers ("errbacks") to. A Deferred is basically a "promise" that a function will have a result eventually.

Meredith L. Patterson
In particular, look at twisted.internet.defer (http://twistedmatrix.com/documents/8.2.0/api/twisted.internet.defer.html).
Nicholas Riley
A: 

What about something like (doc at http://docs.python.org/library/threading.html#module-threading)

import threading

thr = threading.Thread(target=foo, [args=(), kwargs={}])
thr.start() # will run "foo"
....
thr.is_alive() # will return whether foo is running currently
....
thr.join() # will wait till "foo" is done
Drakosha
A: 

Is there any reason not to use threads? You can use the "threading" class. Instead of finished() function use the isAlive(), the result() function could join() the thread and retrieve the result and if you can override the run() and init functions to call the function specified in constructor and save the value somewhere to the instance of the class.

ondra
If it's a computationally expensive function threading won't get you anything (it will probably make things slower actually) since a Python process is limited to one CPU core due to the GIL.
Kurt
@Kurt, while that's true, the OP didn't mention that performance was his concern. There are other reasons for wanting asynchronous behaviour...
Peter Hansen
+11  A: 

You can use the multiprocessing module added in Python 2.6. You can use pools of processes and then get results asynchronously with:

apply_async(func[, args[, kwds[, callback]]])

E.g.:

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    pool = Pool(processes=1)              # Start a worker processes.
    result = pool.apply_async(f, [10], callback) # Evaluate "f(10)" asynchronously calling callback when finished.

This is only one alternative. This module provides lots of facilities to achieve what you want. Also it will be really easy to make a decorator from this.

Lucas S.
It's probably worth bearing in mind that this spawns separate processes rather than separate thread within a process. This might some implications.
A: 

Lucas S., your example does not work, unfortunately. The callback function never gets called.

DataGreed
Hello, it is just an example of what you can do, it is far from a complete working example. Look at multiprocessing docs to see how to use it correctly. And if you do it you can edit my answer with working code.
Lucas S.