We can use both functions to run any async function synchronously:
import asyncio
from asgiref.sync import async_to_sync
asyncio.run(asyncio.sleep(1))
async_to_sync(asyncio.sleep)(1)
What is the difference? Can we always use asyncio.run
instead of async_to_sync
?
async_to_sync() is essentially a more powerful version of the asyncio. run() function in Python's standard library. As well as ensuring threadlocals work, it also enables the thread_sensitive mode of sync_to_async() when that wrapper is used below it.
Async IO takes long waiting periods in which functions would otherwise be blocking and allows other functions to run during that downtime. (A function that blocks effectively forbids others from running from the time that it starts until the time that it returns.)
gather() method - It runs awaitable objects (objects which have await keyword) concurrently.
The asyncio. sleep() method suspends the execution of a coroutine. Coroutines voluntarily yield CPU leading to co-operative multitasking through the await keyword.
They have different purposes. async_to_sync
turns an awaitable into a synchronous callable, and asyncio.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 by sync_to_async
and running inside asynchronous code. It reuses a loop of asynchronous code. Let's take an example:
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)))
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 inner
p = 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With