Django — async_to_sync vs asyncio.run
Differences
They have different purposes.
async_to_sync
turns an awaitable into a synchronous callable, andasyncio.run
executes a coroutine and return the result.According to documentation, a callable from
async_to_sync
works in a subthread.async_to_sync
does not create an event loop per-thread in case when you're inside synchronous code which is produced bysync_to_async
and running inside asynchronous code. It reuses a loop of asynchronous code. Let's take an example:
import asynciofrom asgiref.sync import async_to_sync, sync_to_asyncasync 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 nprint("Result:", asyncio.run(running(3)))
This one will run 4 loops: 1 to call running
and 3 to call from_sync
.
If we use async_to_sync
instead of asyncio.run
inside sync
we will reduce the number of loops to 1 to call running
.
To see it you can wrap new_event_loop
function:
def print_deco(fn, msg): def inner(): res = fn() print(msg, res) return res return innerp = asyncio.get_event_loop_policy()p.new_event_loop = print_deco(p.new_event_loop, "NEW EVENT LOOP:")
You can find a detailed explanation in this post.