2013-10-29 100 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)