Performance
Understanding SmartAsync’s performance characteristics.
Overhead by Scenario
Scenario |
Overhead |
Impact |
|---|---|---|
Sync → Async |
~102μs |
|
Async → Async (cached) |
~1.3μs |
Negligible |
Async → Async (first call) |
~2.3μs |
Context detection |
Async → Sync |
~50-100μs |
Thread pool offloading |
Real-World Impact
For typical I/O operations, SmartAsync overhead is negligible:
Network Requests
Request time: 10-200ms
SmartAsync overhead: ~0.1ms
Impact: < 1%
Database Queries
Query time: 1-50ms
SmartAsync overhead: ~0.1ms
Impact: < 10%
File I/O
Operation time: 1-100ms
SmartAsync overhead: ~0.1ms
Impact: < 10%
When Overhead Matters
SmartAsync may not be suitable for:
Tight loops with thousands of calls
Fast operations (<10μs) called repeatedly
Performance-critical hot paths
In these cases, consider using explicit async/await or refactoring to batch operations.
Optimization Tips
1. Batch Operations
Instead of:
for item in items:
result = await process(item) # Many calls
Do:
results = await asyncio.gather(
*[process(item) for item in items]
)
2. Cache Results
If calling same method repeatedly:
@functools.cache
@smartasync
async def expensive_operation():
...
3. Use Async Context When Possible
Async context has lower overhead (~1-2μs vs ~100μs).
Benchmarking
To benchmark SmartAsync in your application:
import time
# Measure sync context
start = time.perf_counter()
result = obj.method()
sync_time = time.perf_counter() - start
# Measure async context
async def bench():
start = time.perf_counter()
result = await obj.method()
return time.perf_counter() - start
async_time = asyncio.run(bench())
print(f"Sync: {sync_time*1000:.2f}ms")
print(f"Async: {async_time*1000:.2f}ms")