web-dev-qa-db-ja.com

Django — async_to_syncとasyncio.run

両方の関数を使用して、非同期関数を同期的に実行できます。

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を使用できますか?

5
Max Malysh

違い

  1. 彼らは異なる目的を持っています。 async_to_syncはawaitableを同期呼び出し可能に変換し、asyncio.runはコルーチンを実行して結果を返します。

  2. documentation によると、async_to_syncからの呼び出し可能オブジェクトはサブスレッドで機能します。

  3. 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 にあります。

1