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