Can I use sync_to_async for any function in Python?
Question:
Background:
I’m working on a Discord bot that uses requests. The requests are asynchronous, so I’m using the library asgiref.sync.
(I know I obviously can’t use this function for asynchronous functions.)
I implemented sync_to_async into all the requests and things that may take long to process. The function doesn’t produce any error. However, I’m not sure if this actually does anything.
Answers:
Async does not magically make your program runs in parallel. Within an async function there needs to be certain points where the function "gives up control", like when waiting for a response from a remote server.
If the function you ‘converted’ to async either (1) CPU-bound or (2) not giving up control by invoking an await
statement somewhere, or (3) both, then the function will run until completion until it finishes.
To put it in another way: async is cooperative multitasking. Async functions must, at certain points "hands over" control to the async loop to enable others to run.
Can I use sync_to_async for any function in Python?
Yes, but…
does this mean I can convert any function to async to make things run faster and more cohesively (…)?
No. Here’s a code example:
import asyncio
import time
from asgiref.sync import async_to_sync, sync_to_async
def sleep(t0):
time.sleep(1)
print(time.time() - t0)
async def async_sleep(t0):
await asyncio.sleep(1)
print(time.time() - t0)
sync_to_async_sleep = sync_to_async(sleep)
async_to_sync_sleep = async_to_sync(async_sleep)
async def async_main():
print('sync')
t0 = time.time()
sleep(t0)
sleep(t0)
print('nsync_to_async')
t0 = time.time()
await asyncio.gather(
sync_to_async_sleep(t0),
sync_to_async_sleep(t0),
)
print('nasync')
t0 = time.time()
await asyncio.gather(
async_sleep(t0),
async_sleep(t0),
)
def main():
print('nasync_to_sync')
t0 = time.time()
async_to_sync_sleep(t0)
async_to_sync_sleep(t0)
asyncio.run(async_main())
main()
Output:
sync
1.00
2.01
sync_to_async
1.00
2.01
async
1.00
1.00
async_to_sync
1.00
2.01
Evidently, only the "async" case (true async implementation in async context) runs concurrently.
Background:
I’m working on a Discord bot that uses requests. The requests are asynchronous, so I’m using the library asgiref.sync.
(I know I obviously can’t use this function for asynchronous functions.)
I implemented sync_to_async into all the requests and things that may take long to process. The function doesn’t produce any error. However, I’m not sure if this actually does anything.
Async does not magically make your program runs in parallel. Within an async function there needs to be certain points where the function "gives up control", like when waiting for a response from a remote server.
If the function you ‘converted’ to async either (1) CPU-bound or (2) not giving up control by invoking an await
statement somewhere, or (3) both, then the function will run until completion until it finishes.
To put it in another way: async is cooperative multitasking. Async functions must, at certain points "hands over" control to the async loop to enable others to run.
Can I use sync_to_async for any function in Python?
Yes, but…
does this mean I can convert any function to async to make things run faster and more cohesively (…)?
No. Here’s a code example:
import asyncio
import time
from asgiref.sync import async_to_sync, sync_to_async
def sleep(t0):
time.sleep(1)
print(time.time() - t0)
async def async_sleep(t0):
await asyncio.sleep(1)
print(time.time() - t0)
sync_to_async_sleep = sync_to_async(sleep)
async_to_sync_sleep = async_to_sync(async_sleep)
async def async_main():
print('sync')
t0 = time.time()
sleep(t0)
sleep(t0)
print('nsync_to_async')
t0 = time.time()
await asyncio.gather(
sync_to_async_sleep(t0),
sync_to_async_sleep(t0),
)
print('nasync')
t0 = time.time()
await asyncio.gather(
async_sleep(t0),
async_sleep(t0),
)
def main():
print('nasync_to_sync')
t0 = time.time()
async_to_sync_sleep(t0)
async_to_sync_sleep(t0)
asyncio.run(async_main())
main()
Output:
sync
1.00
2.01
sync_to_async
1.00
2.01
async
1.00
1.00
async_to_sync
1.00
2.01
Evidently, only the "async" case (true async implementation in async context) runs concurrently.