両方の関数を使用して、非同期関数を同期的に実行できます。
import asyncio
from asgiref.sync import async_to_sync
asyncio.run(asyncio.sleep(1))
async_to_sync(asyncio.sleep)(1)
違いはなんですか? 常にasyncio.run
の代わりにasync_to_sync
を使用できますか?
彼らは異なる目的を持っています。 async_to_sync
はawaitableを同期呼び出し可能に変換し、asyncio.run
はコルーチンを実行して結果を返します。
documentation によると、async_to_sync
からの呼び出し可能オブジェクトはサブスレッドで機能します。
async_to_sync
は、sync_to_async
によって生成された同期コード内で非同期コード内で実行されている場合、スレッドごとにイベントループを作成しません。非同期コードのループを再利用します。例を見てみましょう:
import asyncio
from asgiref.sync import async_to_sync, sync_to_async
async def running(n):
return [await sync_to_async(sync)(i) for i in range(n)]
def sync(n):
# it will create a new loop for every call
return asyncio.run(from_sync(n))
async def from_sync(n):
return n
print("Result:", asyncio.run(running(3)))
これは4つのループを実行します。1はrunning
を呼び出し、3はfrom_sync
を呼び出します。
sync
内でasync_to_sync
の代わりにasyncio.run
を使用する場合、ループの数を1に減らしてrunning
を呼び出します。
それを確認するには、new_event_loop
関数をラップします。
def print_deco(fn, msg):
def inner(): res = fn(); print(msg, res); return res
return inner
p = asyncio.get_event_loop_policy()
p.new_event_loop = print_deco(p.new_event_loop, "NEW EVENT LOOP:")
詳細な説明は post にあります。