Pythonの3.5 async/awaitについての記事やチュートリアルをたくさん読みました。 get_event_loop()とrun_until_complete()を使用するもの、ensure_future()を使用するもの、asyncio.wait()を使用するもの、call_soon()を使用するものがあるため、かなり混乱していると言わざるを得ません。
私は多くの選択肢があるように見えますが、それらが完全に同一であるか、ループを使用する場合とwait()を使用する場合があるかはわかりません。
しかし、すべての例は、待機可能なオブジェクトを返す実際の遅い操作のシミュレーションとして、asyncio.sleep()
で動作します。この行を実際のコードと交換しようとすると、全体が失敗します。一体何が上に書かれたアプローチの違いであり、非同期/待機の準備ができていないサードパーティのライブラリをどのように実行すべきかです。 Quandlサービスを使用して在庫データを取得しています。
import asyncio
import quandl
async def slow_operation(n):
# await asyncio.sleep(1) # Works because it's await ready.
await quandl.Dataset(n) # Doesn't work because it's not await ready.
async def main():
await asyncio.wait([
slow_operation("SIX/US9884981013EUR4"),
slow_operation("SIX/US88160R1014EUR4"),
])
# You don't have to use any code for 50 requests/day.
quandl.ApiConfig.api_key = "MY_SECRET_CODE"
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
私がどれほど失われたと感じているか、並行して走りたいと思っているかどうか、あなたがポイントを得ることを願っています。
サードパーティのライブラリが_async/await
_と互換性がない場合、明らかに簡単に使用することはできません。次の2つのケースがあります。
ライブラリ内の関数が非同期であり、コールバックを提供するとしましょう。
_def fn(..., clb):
...
_
だからあなたができる:
_def on_result(...):
...
fn(..., on_result)
_
その場合、このような関数を次のようにasyncioプロトコルにラップできます。
_from asyncio import Future
def wrapper(...):
future = Future()
def my_clb(...):
future.set_result(xyz)
fn(..., my_clb)
return future
_
(例外でfuture.set_exception(exc)
を使用)
次に、async
を使用して、いくつかのawait
関数でそのラッパーを呼び出すことができます。
_value = await wrapper(...)
_
await
はどのFuture
オブジェクトでも機能することに注意してください。 wrapper
をasync
として宣言する必要はありません。
ライブラリ内の関数が同期の場合、別のスレッドで実行できます(おそらく、そのためのスレッドプールを使用します)。コード全体は次のようになります。
_import asyncio
import time
from concurrent.futures import ThreadPoolExecutor
# Initialize 10 threads
THREAD_POOL = ThreadPoolExecutor(10)
def synchronous_handler(param1, ...):
# Do something synchronous
time.sleep(2)
return "foo"
# Somewhere else
async def main():
loop = asyncio.get_event_loop()
futures = [
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
]
await asyncio.wait(futures)
for future in futures:
print(future.result())
with THREAD_POOL:
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
_
何らかの理由でスレッドを使用できない場合、そのようなライブラリを使用すると、非同期コード全体が無意味になります。
ただし、非同期で同期ライブラリを使用することは、おそらく悪い考えです。あまり多くは得られませんが、コードはかなり複雑になります。