2017-04-05 12 views
14

aiohttpを使用して、TCPリクエストを別のサーバーに送信するAPIサーバーを構築しています。 TCPリクエストを送信するモジュールは、私の目的のために同期とブラックボックスです。だから私の問題は、これらの要求がAPI全体をブロックしているということです。私はモジュールのリクエストを非同期コルーチンに包み込み、残りのAPIをブロックしない方法が必要です。同期関数を非同期コルーチンにラップする方法はありますか?

それでは、簡単な例としてsleepを使用して、何とか非ブロックコルーチンに時間のかかる同期コードをラップする方法があり、このような何か:

async def sleep_async(delay): 
    # After calling sleep, loop should be released until sleep is done 
    yield sleep(delay) 
    return 'I slept asynchronously' 
+1

。コラボレーションがブロックされると、要求が完了した後にのみ制御(yield)が返されるため、協調マルチタスクでは、望ましい動作を得ることができません。 –

+1

aiohttpはhttpに適しています。 http以外のTCPの場合、asyncioで十分です。 – Udi

答えて

15

は最終的に私がで答えを見つけましたthis thread。私が探していた方法はrun_in_executorです。これにより、イベントループをブロックすることなく非同期に同期関数を実行することができます。私は上記の投稿sleep例で

、それは次のようになります。

import asyncio 
from time import sleep 
from concurrent.futures import ProcessPoolExecutor 

async def sleep_async(loop, delay): 
    # Can set executor to None if a default has been set for loop 
    await loop.run_in_executor(ProcessPoolExecutor(), sleep, delay) 
    return 'I slept asynchronously' 

はまた、以下の答えを参照してください - > How do we call a normal function where a coroutine is expected?あなたは常にI/Oでブロック

+8

'ProcessPoolExecutor'は、新しいPythonインタプリタ全体を起動するため、コストが高くなります。複数のプロセッサーを使用するCPU集約型のタスクがある場合に使用されます。 ThreadPoolExecutorを代わりに使用することを検討してください。これはスレッドを使用します。 – Oleg

+3

ありがとうございました。元の例ではプロセスプールを使用していましたが、 'ThreadPoolExecutor'はもう少しの研究の後に私が使い終わったものです。まだ少し気が散っているようですが、これまでのところ一緒に握っています。 –

+2

新しいエグゼキュータを作成するのではなく、 'loop.run_in_executor(executor = None、func、* args)'を呼び出すことでデフォルトのエグゼキュータを使用するほうが簡単かもしれません([documentation](https:// docs。 python.org/3/library/asyncio-eventloop.html#asyncio.AbstractEventLoop.run_in_executor))。 –

関連する問題