2016-10-16 4 views
0

私は竜巻とPythonの初心者です。数日前、私は非ブロッキングの残りのAPIを書くようになりましたが、私はまだ使命を達成できませんでした。このエンドポイント「localhost:8080/async」に同時に2つのリクエストを送信すると、2番目のリクエストは20秒後に応答します。それは私が間違っていることを説明している。Python Tornado Gen.coroutineブロックリクエスト

MAX_WORKERS = 4 
class ASYNCHandler(tornado.web.RequestHandler): 
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS) 
    counter = 0 

    def pow_task(self, x, y): 
     time.sleep(10) 
     return pow(x,y) 

    async def background_task(self): 
     future = ASYNCHandler.executor.submit(self.pow_task, 2, 3) 
     return future 

    @gen.coroutine 
    def get(self, *args, **kwargs): 
     future = yield from self.background_task() 
     response= dumps({"result":future.result()}, default=json_util.default) 
     print(response) 


application = tornado.web.Application([ 
     ('/async', ASYNCHandler), 
     ('/sync', SYNCHandler), 
    ], db=db, debug=True) 
application.listen(8888) 
tornado.ioloop.IOLoop.current().start() 

答えて

0

そのThreadPoolExecutor将来、基本的にブロック竜巻のイベントループを返します。竜巻チームの誰かがこれを読んで、それがなぜあるのか知っていれば、彼らは説明をお願いしますか?私は竜巻のスレッドでいくつかのことをするつもりだったが、この質問に対処した後、私はそれが当初想定していたほど単純ではないことがわかった。いずれにせよ、ここに何を期待したコードである(誰でもすぐにそれを実行できるように、私は少しをあなたの元の例を下にトリミングされました):

from concurrent.futures import ThreadPoolExecutor 
from json import dumps 
import time 
from tornado.platform.asyncio import to_tornado_future 
from tornado.ioloop import IOLoop 
from tornado import gen, web 

MAX_WORKERS = 4 

class ASYNCHandler(web.RequestHandler): 
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS) 
    counter = 0 

    def pow_task(self, x, y): 
     time.sleep(5) 
     return pow(x,y) 

    async def background_task(self): 
     future = self.executor.submit(self.pow_task, 2, 3) 
     result = await to_tornado_future(future) # convert to tornado future 
     return result 

    @gen.coroutine 
    def get(self, *args, **kwargs): 
     result = yield from self.background_task() 
     response = dumps({"result": result}) 
     self.write(response) 


application = web.Application([ 
     ('/async', ASYNCHandler), 
    ], debug=True) 
application.listen(8888) 
IOLoop.current().start() 

主な違いはbackground_tasks()方法です。 asyncioの未来をtornadoに変換し、結果を待ってから結果を返します。あなたが質問で提供したコードは、background_task()から降伏したとき何らかの理由でブロックされ、あなたはawaitに未来が竜巻の将来ではなかったために結果できませんでした。

この単純な例では、単一のスレッド/非同期のデザインを使用して簡単に実装できます。コードはスレッドなしでも実行できる可能性があります。スレッドは実装が簡単ですが、同じように簡単に間違いが起きやすく、非常に固い状況につながる可能性があります。スレッドコードを書くときには、this photoを覚えておいてください:)

関連する問題