2013-10-29 4 views
6

Ich habe einige asynchrone Funktionen mit tornado gen.coroutine, die ich normalerweise als Teil einer Tornado-basierten Webanwendung verwenden. Allerdings möchte ich einige von ihnen aus einem einfachen alten Python-Skript aufrufen, um einige Administrationsaufgaben zu erledigen. Wie mache ich das?Verwenden Sie Tornado Async-Code in einem regulären Python-Skript

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:

Ein konkreteres Beispiel:

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) 

Ausführen dieser Ausgänge:

myfunc 
aaf 
+1

Leider eine solche offensichtliche Frage zu fragen, aber was hindert Sie daran some_internal_stuff.another_async_func Aufruf (x) direkt und auf das Ergebnis warten? Hat die Funktion, die Sie aufrufen, Abhängigkeiten von Tornado, die das verhindern? –

+0

@rod: Die Idee ist, dass 'another_async_func' eine weitere Tornado' @ asynchrone' Methode ist, die normalerweise bei einem Tornado 'IOLoop' läuft. Ich könnte 'another_async_func' ausführen und einen' callback' übergeben, aber ohne Tornado läuft die Zeile nach dem yield in 'myfunc' niemals, und der Callback, den ich übergeben habe, wird nicht aufgerufen. – rakslice

Antwort

16

Es gibt eine integrierte Methode run_sync in IOLoop a laufen Einzelruf und dann s top die Schleife, so ist es ziemlich trivial, nur eine Ereignisschleife zu einem einfachen Python-Skript hinzuzufügen, vorausgesetzt, Sie haben Tornado in der PYTHONPATH.

Mit dem konkreten Beispiel:

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) 

Diese Ausgänge:

myfunc 
aaf 
back 
Callback called with 2 

Beachten Sie, dass run_sync nicht nisten gut; Wenn Sie run_sync in einer Funktion aufrufen, die von run_sync auf demselben IOLoop aufgerufen wird, wird die Beendigung des inneren Anrufs die IOLoop und nicht weiter yield s stoppen, nachdem der innere Aufruf zurückgegeben wird.

1

Hier ist eine andere Möglichkeit, Threads, dass das Problem der Komplexität und je nach Bedarf funktionieren würde:

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)