Domanda

I have some asynchronous functions using tornado gen.coroutine that I normally use as part of a tornado-based web application. However, I want to call some of them from a plain old python script to do some administration tasks. How do I do this?

from tornado import gen

import some_internal_stuff

@gen.coroutine
def myfunc(x):
    y = yield some_internal_stuff.another_async_func(x)
    raise gen.Return(y)

if __name__ == "__main__":
    # What do I put here to call myfunc(1) and get the async return value?
    pass

Update:

A more concrete example:

from tornado import gen

@gen.coroutine
def another_async_func(x):
    print "aaf"
    raise gen.Return(x + 1)

@gen.coroutine
def myfunc(x):
    print "myfunc"
    y = yield another_async_func(x)
    print "back"
    raise gen.Return(y)

def callback(y):
    print "Callback called with %d" % y

if __name__ == "__main__":
    myfunc(1, callback=callback)

Running this outputs:

myfunc
aaf
È stato utile?

Soluzione

There's a built-in method run_sync in IOLoop to run a single call and then stop the loop, so it's pretty trivial to just add an event loop to a plain python script provided you have tornado in the PYTHONPATH.

With the concrete example:

from tornado import gen, ioloop

@gen.coroutine
def another_async_func(x):
    print "aaf"
    raise gen.Return(x + 1)

@gen.coroutine
def myfunc(x):
    print "myfunc"
    y = yield another_async_func(x)
    print "back"
    raise gen.Return(y)

@gen.coroutine
def main():
    y = yield myfunc(1)
    print "Callback called with %d" % y

if __name__ == "__main__":
    ioloop.IOLoop.instance().run_sync(main)

This outputs:

myfunc
aaf
back
Callback called with 2

Note that run_sync doesn't nest well; if you call run_sync in a function called by run_sync on the same IOLoop the completion of the inner call will stop the IOLoop and no further yields after the inner call will return.

Altri suggerimenti

Here's another possibility, using threads, that would work depending on the problem complexity and your needs:

if __name__ == "__main__":
    import threading, time
    # The tornado IO loop doesn't need to be started in the main thread
    # so let's start it in another thread:
    t = threading.Thread(target=IOLoop.instance().start)
    t.daemon = True
    t.start()

    myfunc(1, callback=callback)
    # now the main loop needs wait; you can do that by polling a value, sleeping,
    # or waiting on a lock. I've chosen to sleep here, but a lock is probably more
    # appropriate; and, once computation is done, release the lock.
    time.sleep(2)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top