You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While testing, I noticed that nesting calls to async_to_sync and sync_to_async causes two calls to sync_to_async(thread_sensitive=True) to run in different threads if you call sync_to_async(thread_sensitive=False) in between those two calls. It seems that once sync_to_async is called with thread_sensitive=False, all subsequent (nested) calls with thread_sensitive=True will run on the new parent thread rather than the main thread.
Example Code
import threading
from asgiref.sync import async_to_sync, sync_to_async
def method5():
print(f"Third call to sync_to_sync: {threading.get_ident()}")
async def method4():
print(f"Third call to async_to_sync: {threading.get_ident()}")
await sync_to_async(method5)()
def method3():
print(f"Second call to sync_to_async: {threading.get_ident()}")
async_to_sync(method4)()
async def method2():
print(f"Second call to async_to_sync: {threading.get_ident()}")
await sync_to_async(method3, thread_sensitive=False)()
def method1():
print(f"First call to sync_to_async: {threading.get_ident()}")
async_to_sync(method2)()
async def start():
print(f"First call to async_to_sync: {threading.get_ident()}")
await sync_to_async(method1)()
print(f"Main thread: {threading.get_ident()}")
async_to_sync(start)()
Output
Main thread: 4593313280
First call to async_to_sync: 123145368514560
First call to sync_to_async: 4593313280
Second call to async_to_sync: 123145368514560
Second call to sync_to_async: 123145373769728
Third call to async_to_sync: 123145368514560
Third call to sync_to_sync: 123145373769728
As you can see, the main thread is 4593313280. The first call to sync_to_async(thread_sensitive=True) runs on the main thread, as expected. The second call to sync_to_async(thread_sensitive=False) creates a new thread (123145373769728), as expected. However, the third and fourth calls to sync_to_async(thread_sensitive=True) run on thread 123145373769728 rather than the main thread.
This seems to contradict the behavior described in the README:
All synchronous code called through SyncToAsync and marked with thread_sensitive should run in the same thread as each other (and if the outer layer of the program is synchronous, the main thread)
Is this a bug? Or is this expected behavior, and merely a gap in the documentation?
Thanks!
Charlie
The text was updated successfully, but these errors were encountered:
charliesteele
changed the title
Nested sync_to_async calls do not run in the same thread.
Nested sync_to_async(thread_sensitive=True) calls do not run in the same thread.
Nov 18, 2022
Hmm, it's neither a bug nor necessarily intended - what is happening is that thread_sensitive is finding the first sync thread above it in the stack that it can reuse and doing so.
I'm tempted to just document the behaviour rather than trying to fix it, trying to undo this would be the stuff of nightmares.
While testing, I noticed that nesting calls to
async_to_sync
andsync_to_async
causes two calls tosync_to_async(thread_sensitive=True)
to run in different threads if you callsync_to_async(thread_sensitive=False)
in between those two calls. It seems that oncesync_to_async
is called withthread_sensitive=False
, all subsequent (nested) calls withthread_sensitive=True
will run on the new parent thread rather than the main thread.Example Code
Output
As you can see, the main thread is
4593313280
. The first call tosync_to_async(thread_sensitive=True)
runs on the main thread, as expected. The second call tosync_to_async(thread_sensitive=False)
creates a new thread (123145373769728
), as expected. However, the third and fourth calls tosync_to_async(thread_sensitive=True)
run on thread123145373769728
rather than the main thread.This seems to contradict the behavior described in the README:
Is this a bug? Or is this expected behavior, and merely a gap in the documentation?
Thanks!
Charlie
The text was updated successfully, but these errors were encountered: