2013-10-29 67 views
6

我有一些异步功能,使用tornado gen.coroutine,我通常将其用作基于龙卷风的Web应用程序的一部分。不过,我想从一个普通的旧Python脚本中调用其中的一些来执行一些管理任务。我该怎么做呢?在普通Python脚本中使用龙卷风异步代码

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 

更新:

更具体的例子:

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) 

运行此输出:

myfunc 
aaf 
+1

对不起,问这样一个明显的问题,但什么阻止你打电话some_internal_stuff.another_async_func(x)的直接并等待结果?你调用的函数是否依赖Tornado来防止这种情况发生? –

+0

@rod:想法是'another_async_func'是另一个龙卷风'@异步'方法,通常在有龙卷风'IOLoop'的情况下运行。我可以运行'another_async_func'并将它传递给'callback',但没有龙卷风运行,'myfunc'中的产出之后的行永远不会运行,并且我传递的回调不会被调用。 – rakslice

回答

16

有一个内置的方法run_syncIOLoop运行单一电话,然后s顶部的循环,所以只需要添加一个事件循环到一个普通的python脚本,只要你在PYTHONPATH中有龙卷风就可以了。

随着具体的例子:

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) 

此输出:

myfunc 
aaf 
back 
Callback called with 2 

注意run_sync不巢井;如果您在同一个IOLooprun_sync调用run_sync的功能,内部呼叫的完成将停止IOLoop,内部呼叫返回后不会再有yield

1

这里的另一种可能性,使用线程,这将取决于问题的复杂性和需求的工作:

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)