0
# Sync/Async Conversion
1
2
Core functionality for converting between synchronous and asynchronous functions, handling context propagation, thread management, and event loop integration automatically. These utilities enable seamless integration between sync and async codebases.
3
4
## Capabilities
5
6
### Function Decorators
7
8
Convert functions between sync and async execution contexts with automatic context variable propagation and proper thread/event loop management.
9
10
```python { .api }
11
def sync_to_async(func=None, *, thread_sensitive=True, executor=None):
12
"""
13
Convert a synchronous function to an asynchronous one.
14
15
Parameters:
16
- func: callable, the synchronous function to convert
17
- thread_sensitive: bool, whether to run in thread-sensitive mode (default True)
18
- executor: Executor, custom executor for running sync code (optional)
19
20
Returns:
21
SyncToAsync wrapper that can be called with await
22
"""
23
24
def async_to_sync(awaitable=None, *, force_new_loop=False):
25
"""
26
Convert an asynchronous function to a synchronous one.
27
28
Parameters:
29
- awaitable: callable, the async function/coroutine to convert
30
- force_new_loop: bool, whether to force creation of new event loop (default False)
31
32
Returns:
33
AsyncToSync wrapper that can be called synchronously
34
"""
35
```
36
37
### Conversion Classes
38
39
Direct access to the underlying conversion classes for advanced use cases and custom integration.
40
41
```python { .api }
42
class SyncToAsync:
43
"""Generic utility class to convert sync functions to async."""
44
45
def __init__(self, func, thread_sensitive=True, executor=None):
46
"""
47
Initialize sync-to-async converter.
48
49
Parameters:
50
- func: callable, synchronous function to wrap
51
- thread_sensitive: bool, run in thread-sensitive mode
52
- executor: Executor, custom executor instance
53
"""
54
55
def __call__(self, *args, **kwargs):
56
"""
57
Execute wrapped function asynchronously.
58
59
Returns:
60
Coroutine that will execute the sync function
61
"""
62
63
def __get__(self, parent, objtype):
64
"""Descriptor protocol support for method binding."""
65
66
class AsyncToSync:
67
"""Generic utility class to convert async functions to sync."""
68
69
def __init__(self, awaitable, force_new_loop=False):
70
"""
71
Initialize async-to-sync converter.
72
73
Parameters:
74
- awaitable: callable, async function to wrap
75
- force_new_loop: bool, force new event loop creation
76
"""
77
78
def __call__(self, *args, **kwargs):
79
"""
80
Execute wrapped function synchronously.
81
82
Returns:
83
Result of the async function executed synchronously
84
"""
85
86
def __get__(self, parent, objtype):
87
"""Descriptor protocol support for method binding."""
88
```
89
90
### Thread Context Management
91
92
Advanced context management for thread-sensitive operations and cross-context execution.
93
94
```python { .api }
95
class ThreadSensitiveContext:
96
"""Async context manager for thread-sensitive mode."""
97
98
async def __aenter__(self):
99
"""Enter thread-sensitive async context."""
100
101
async def __aexit__(self, exc, value, tb):
102
"""Exit thread-sensitive async context."""
103
```
104
105
### Coroutine Function Utilities
106
107
Utilities for detecting and marking coroutine functions, particularly useful for framework integration.
108
109
```python { .api }
110
def iscoroutinefunction(func):
111
"""
112
Check if something is a coroutine function.
113
114
Parameters:
115
- func: callable, function to check
116
117
Returns:
118
bool: True if func is a coroutine function
119
"""
120
121
def markcoroutinefunction(func):
122
"""
123
Decorator to mark functions as coroutine functions.
124
125
Parameters:
126
- func: callable, function to mark
127
128
Returns:
129
callable: The marked function
130
"""
131
```
132
133
## Usage Examples
134
135
### Basic Function Conversion
136
137
```python
138
from asgiref.sync import sync_to_async, async_to_sync
139
import time
140
import asyncio
141
142
# Convert sync function to async
143
@sync_to_async
144
def sync_operation():
145
time.sleep(1) # Simulate blocking operation
146
return "sync result"
147
148
# Convert async function to sync
149
@async_to_sync
150
async def async_operation():
151
await asyncio.sleep(1) # Simulate async operation
152
return "async result"
153
154
# Usage in async context
155
async def async_main():
156
result = await sync_operation()
157
print(result) # "sync result"
158
159
# Usage in sync context
160
def sync_main():
161
result = async_operation()
162
print(result) # "async result"
163
```
164
165
### Thread-Sensitive vs Thread-Insensitive
166
167
```python
168
from asgiref.sync import sync_to_async
169
import threading
170
171
# Thread-sensitive (default) - runs in same thread
172
@sync_to_async(thread_sensitive=True)
173
def thread_sensitive_func():
174
return threading.current_thread().name
175
176
# Thread-insensitive - can run in any thread
177
@sync_to_async(thread_sensitive=False)
178
def thread_insensitive_func():
179
return "Can run anywhere"
180
181
async def demonstrate():
182
# Will run in specific thread context
183
result1 = await thread_sensitive_func()
184
185
# Can run in thread pool
186
result2 = await thread_insensitive_func()
187
```
188
189
### Custom Executor
190
191
```python
192
from asgiref.sync import sync_to_async
193
from concurrent.futures import ThreadPoolExecutor
194
195
# Use custom executor
196
custom_executor = ThreadPoolExecutor(max_workers=2)
197
198
@sync_to_async(executor=custom_executor)
199
def cpu_intensive_task():
200
# CPU-bound work
201
return sum(i * i for i in range(1000000))
202
203
async def main():
204
result = await cpu_intensive_task()
205
print(f"Result: {result}")
206
```
207
208
### Method Conversion
209
210
```python
211
from asgiref.sync import sync_to_async, async_to_sync
212
213
class DatabaseManager:
214
@sync_to_async
215
def get_user(self, user_id):
216
# Simulate database query
217
return {"id": user_id, "name": f"User {user_id}"}
218
219
@async_to_sync
220
async def async_get_user(self, user_id):
221
# Simulate async database query
222
await asyncio.sleep(0.1)
223
return {"id": user_id, "name": f"Async User {user_id}"}
224
225
# Usage
226
db = DatabaseManager()
227
228
async def async_usage():
229
user = await db.get_user(123)
230
print(user)
231
232
def sync_usage():
233
user = db.async_get_user(456)
234
print(user)
235
```