简体   繁体   中英

Use tornado async code in a regular python script

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

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 yield s after the inner call will return.

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM