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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With