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.

Asked By: Blue Robin

||

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.

Answered By: pepoluan

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.

Answered By: aaron
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.