2016-10-26 8 views
0

私は、トルネードの非同期GET要求ハンドラで(実際にサードパーティのライブラリから)低速ブロックメソッドを実行したいと思います。この方法は、ちょうどとする:asyncioのrun_in_executorが竜巻のgetハンドラをブロックするのはなぜですか?

def blocking_method(uid): 
    print("slow method started: ", uid) 
    time.sleep(10) 
    print("slow method done: ", uid) 
    return "slow method ({}) result".format(uid) 

はまた、私はasyncioのイベントループで竜巻サーバーを実行していることを好む:

if __name__ == '__main__': 
    tornado.platform.asyncio.AsyncIOMainLoop().install() 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(make_app()) 
    loop.run_forever() 

私はおよそ@run_in_executorデコレータを知っていたが、私はasyncioを使用するので、それは、私には適していませんです。非同期コルーチンでブロック方法を実行するには、asyncio.get_event_loop()run_in_executorメソッドを使用する必要があります。ここでは、それを行う方法の例であるthis答えから:

import asyncio 

async def main(): 
    loop = asyncio.get_event_loop() 
    executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) 
    future1 = loop.run_in_executor(executor, blocking_method, 1) 
    future2 = loop.run_in_executor(executor, blocking_method, 2) 
    response1 = await future1 
    response2 = await future2 
    print(response1) 
    print(response2) 

if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(main()) 

そして、それは完璧に動作しますが、ここでは前のスクリプトからの出力は次のとおりです。

slow method started: 1 
slow method started: 2 
slow method done: 2 
slow method done: 1 
slow method (1) result 
slow method (2) result 

しかし、私はasync def getに非常に同じ技術を使用している場合竜巻のメソッドRequestHandler:

class AsyncHandler(tornado.web.RequestHandler): 

    async def get(self): 
     # simple counter to distinguish requests 
     self.application.counter += 1 
     in_msg = "Registered request #{}, working...".format(self.application.counter) 
     print(in_msg) 
     loop = asyncio.get_event_loop() 
     future = loop.run_in_executor(self.application.executor, 
             blocking_method, 
             self.application.counter) 
     result = await future 
     out_msg = "Request processed, result: {}".format(result) 
     print(out_msg) 
     self.write(out_msg) 

ハンドラのメソッドをブロックします。

Registered request #1, working... 
slow method started: 1 
Registered request #2, working... 
slow method started: 2 
slow method done: 1 
Request processed, result: slow method (1) result 
slow method done: 2 
Request processed, result: slow method (2) result 

しかし、リクエストが結果的にをを実行している:私はいくつかのブラウザタブでhttp://localhost:8888/を開いた場合、他の言葉では、その後、私は 2つの要求は、次の出力で、並行して作業を期待、(それは2になりましょう) :

Registered request #1, working... 
slow method started: 1 
slow method done: 1 
Request processed, result: slow method (1) result 
Registered request #2, working... 
slow method started: 2 
slow method done: 2 
Request processed, result: slow method (2) result 

だからどこが間違っていますか?リクエストハンドラを並行して実行できるようにするにはどうすればよいですか?

import asyncio 
import concurrent.futures 
import time 

import tornado.web 
import tornado.platform 


def blocking_method(uid): 
    print("slow method started: ", uid) 
    time.sleep(10) 
    print("slow method done: ", uid) 
    return "slow method ({}) result".format(uid) 


class AsyncHandler(tornado.web.RequestHandler): 

    async def get(self): 
     # simple counter to distinguish requests 
     self.application.counter += 1 
     in_msg = "Registered request #{}, working...".format(self.application.counter) 
     print(in_msg) 
     loop = asyncio.get_event_loop() 
     future = loop.run_in_executor(self.application.executor, 
             blocking_method, 
             self.application.counter) 
     result = await future 
     out_msg = "Request processed, result: {}".format(result) 
     print(out_msg) 
     self.write(out_msg) 

async def make_app(): 
    handlers = [(r"/", AsyncHandler)] 
    app = tornado.web.Application(handlers, debug=True) 
    app.executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) 
    app.counter = 0 
    app.listen(8888) 

if __name__ == '__main__': 
    tornado.platform.asyncio.AsyncIOMainLoop().install() 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(make_app()) 
    loop.run_forever() 
+2

'run_in_executor'はブロックされません。要求を順番に実行するのはあなたのウェブブラウザです。この[類似の質問](http://stackoverflow.com/questions/40195734/python-3-5-aiohttp-blocks-even-when-using-async-await)を参照してください。 – Vincent

答えて

2

ブラウザを使用すると、2つの異なるタブで同じページをロードしようとしていることを認識し、最初が完了するまで、第2の要求を遅らせます:ここでは

は私の問題を説明する完全なスクリプトです。

http://www.tornadoweb.org/en/latest/faq.html#why-isn-t-this-example-with-time-sleep-running-in-parallel

  • それらを一意にするために、あなたのURLに何かを追加します。どちらのタブにもhttp://localhost:8888の代わりに、http://localhost:8888/?x=1を1に、http://localhost:8888/?x=2をもう一方にロードします。
  • 2つの異なるブラウザを使用します。たとえば、同じURLがChromeタブに読み込まれている間でも、FirefoxはURLを読み込むことができます。
+0

oh my gosh。私はこのために一日を過ごす...ありがとう。 –

関連する問題