2016-07-01 11 views
1

私はトルネードからコルーチンを理解する過程にあるので、すべてをシンプルに保ち、ペーストするコードが多くなるほどよいでしょう。トルネードコルーチン - カスタム関数

私が欲しいのは、自分の手作りの機能を非同期にすることです。

ドキュメントにあるすべての例は、同じ「隠された」部分、つまりAsyncHTTPClientに該当します。私はHTTPコールをするつもりはない。だから、そのクラスで私に例を挙げてはいけません。私は最初から何かを作りたいと思っています。私はすべての可能性を試しましたTornado coroutine

今のところ私はbashの睡眠でテストしています。

import tornado.web 
import tornado.httpserver 
import tornado.gen 
import tornado.concurrent 
import subprocess 
import os 

@tornado.gen.coroutine 
def letswait(): 
    fut = tornado.concurrent.Future() 
    subprocess.check_output(["sleep", "5"]) 
    fut.set_result(42) 
    return fut 

class TestHandler1(tornado.web.RequestHandler): 
    @tornado.gen.coroutine 
    def get(self): 
     value = yield letswait() 
     self.render("test.html", num=value) 

class TestHandler2(tornado.web.RequestHandler): 
    def get(self): 
     self.render("test.html", num=66) 

class Application(tornado.web.Application): 
    def __init__(self): 
     DIRNAME = os.path.dirname(__file__) 
     STATIC_PATH = os.path.join(DIRNAME, '../static') 
     TEMPLATE_PATH = os.path.join(DIRNAME, '../template') 
     sets = { 
      "template_path":TEMPLATE_PATH, 
      "static_path":STATIC_PATH, 
      "debug":True, 
     } 
     tornado.web.Application.__init__(self, [ 
      (r"/test1", TestHandler1), 
      (r"/test2", TestHandler2), 
     ], **sets) 

def main(): 
    http_server = tornado.httpserver.HTTPServer(Application()) 
    http_server.listen(8888) 
    print "Let s start" 
    tornado.ioloop.IOLoop.instance().start() 

if __name__ == "__main__": 
    main() 

私がtest1にアクセスすると、test2にアクセスする前に呼び出しが返るのを待つ必要があります。私が理解したところから、gen.sleep(5)を使用する必要があります。しかしそれは単なる例です。たとえば、sleep 5をbashで実行する代わりに、実行するのに時間がかかるssh somewhere 'do_something'を実行しています。

「この機能は非同期ではありません」と言われました。だから私の質問は、カスタム関数を非同期にする方法です。

EDIT:少し検索したところで、私はここに竜巻のプロセスhttps://gist.github.com/FZambia/5756470があるのを見ました。しかし、私のサブプロセスはサードパーティ製のものなので、上書きできるものではありません。だから私の質問も、私はそのgen.coroutineシステムとサードパーティのライブラリを統合するのですか?

SOLUTION:私はここに同様の質問求めてきました

import tornado.web 
import tornado.httpserver 
import tornado.gen 
import tornado.concurrent 
import subprocess 
import os 

from concurrent import futures 

# Create a threadpool, and this can be shared around different python files 
# which will not re-create 10 threadpools when we call it. 
# we can a handful of executors for running synchronous tasks 

# Create a 10 thread threadpool that we can use to call any synchronous/blocking functions 
executor = futures.ThreadPoolExecutor(10) 

def letswait(): 
    result_future = tornado.concurrent.Future() 
    subprocess.check_output(["sleep", "5"]) 
    result_future.set_result(42) 
    return result_future 

class TestHandler1(tornado.web.RequestHandler): 
    @tornado.gen.coroutine 
    def get(self): 
     value = yield executor.submit(letswait) 
     self.render("test.html", num=value) 

class TestHandler2(tornado.web.RequestHandler): 
    def get(self): 
     self.render("test.html", num=66) 

class Application(tornado.web.Application): 
    def __init__(self): 
     DIRNAME = os.path.dirname(__file__) 
     STATIC_PATH = os.path.join(DIRNAME, '../static') 
     TEMPLATE_PATH = os.path.join(DIRNAME, '../template') 
     sets = { 
      "template_path":TEMPLATE_PATH, 
      "static_path":STATIC_PATH, 
      "debug":True, 
     } 
     tornado.web.Application.__init__(self, [ 
      (r"/test1", TestHandler1), 
      (r"/test2", TestHandler2), 
     ], **sets) 

def main(): 
    http_server = tornado.httpserver.HTTPServer(Application()) 
    http_server.listen(8888) 
    print "Let s start" 
    tornado.ioloop.IOLoop.instance().start() 

if __name__ == "__main__": 
    main() 
+0

.result()を削除できますか?それは私の間違いでした。歩留まりは自動的に結果を得るはずです。あなたが結果を待っている可能性があります()と、それはブロックになります。 – user1157751

答えて

4

::私は解決策持っている以下のコメントのおかげで問題があなたの機能がCPUバインドされる可能性がありますされていることをPython Tornado - Confused how to convert a blocking function into a non-blocking function

を、唯一の方法はエグゼキュータを使用することです。 、

@gen.coroutine 
def get(self): 
    json = yield executor.submit(some_long_running_function) 

このタスクはさておき設定し、独立して実行されますyieldキーワードがあるので、純粋なスレッドをしながら、竜巻は、他のいくつかのことを行います。

from concurrent import futures 

# Create a threadpool, and this can be shared around different python files 
# which will not re-create 10 threadpools when we call it. 
# we can a handful of executors for running synchronous tasks 

# Create a 10 thread threadpool that we can use to call any synchronous/blocking functions 
executor = futures.ThreadPoolExecutor(10) 

次に、あなたのような何かを行うことができます現在実行中のプロセスとプロセスの間を切り替えます。私にとってはうまくいくようです。

つまり、executorでサブプロセスをラップすると、非同期で処理されます。

エグゼキュータを使用したくない場合は、関数をステートマシンの方法で実装する必要があるようです。

別の記事:https://emptysqua.re/blog/motor-internals-how-i-asynchronized-a-synchronous-library/

お知らせ桃子(Postgresの)、およびモーター(MongoDBは)、すべてのI/Oバウンドであることを。

編集: 私はトルネードの用途が分かりません。私は多くのI/Oを実行するときにI/O境界になっているので、私はTornadoを使用します。しかし、あなたの使用がより多くのCPUに縛られているかどうかは、Flaskを見たいと思うかもしれません。 GunicornとFlaskを使って簡単に何かを作成し、複数のコアを利用することができます。 Tornadoでマルチスレッドまたはマルチコアを使用しようとすると、たくさんの頭痛を引き起こす可能性があります。なぜなら、Tornadoの多くのものはスレッドセーフではないからです。

編集2:.result()呼び出しを削除しました。

+0

あなたはsome_long_running_functionに何を入れますか?私はあなたの推薦に続いて私のテストを変更しました...まだ運がない(アップデートを確認してください)。 – Regnoult

+0

私にコードを教えてもらえますか?長い実行関数は、基本的に角かっこのない関数名です。任意の変数はコンマで渡されます。 – user1157751

+0

それはそれでした!私はそれの解決策を持って私の質問を更新しています – Regnoult