Comment Maîtriser la Programmation Asynchrone en Python: Async/Await vs Threading
# Comment Maîtriser la Programmation Asynchrone en Python: Async/Await vs Threading
La programmation asynchrone en Python peut sembler complexe au premier abord. Découvrez les différences entre async/await, threading et multiprocessing, et quand les utiliser.
## Le Problème
Imaginons que vous devez récupérer des données de 10 APIs différentes:
```python
# Approche Naïve (Synchrone) - 10+ secondes
import requests
import time
start = time.time()
for i in range(10):
response = requests.get(f'https://api.example.com/data/{i}')
print(f"Response {i}: {response.json()}")
print(f"Temps: {time.time() - start:.2f}s") # ~10+ secondes
import requests
import threading
import time
start = time.time()
results = []
def fetch_data(url):
response = requests.get(url)
results.append(response.json())
threads = []
for i in range(10):
t = threading.Thread(
target=fetch_data,
args=(f'https://api.example.com/data/{i}',)
)
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"Temps: {time.time() - start:.2f}s") # ~1-2 secondes
Avantages:
Simple à comprendre
Bon pour les I/O bound tasks
Inconvénients:
Overhead des threads
GIL (Global Interpreter Lock) limite le parallelisme
Code moins lisible
Solution 2: Async/Await (Moderne)
import aiohttp
import asyncio
import time
async def fetch_data(session, url):
async with session.get(url) as response:
return await response.json()
async def main():
start = time.time()
async with aiohttp.ClientSession() as session:
tasks = [
fetch_data(session, f'https://api.example.com/data/{i}')
for i in range(10)
]
results = await asyncio.gather(*tasks)
print(f"Temps: {time.time() - start:.2f}s") # ~0.5-1 secondes
print(f"Résultats: {len(results)}")
asyncio.run(main())
Avantages:
Plus rapide que threading
Code lisible et maintenable
Pas de GIL
Parfait pour les I/O operations
Inconvénients:
Courbe d'apprentissage
Toute la chaîne doit être async
Solution 3: Multiprocessing (CPU Bound)
from multiprocessing import Pool
import time
def cpu_intensive_task(n):
total = sum(i * i for i in range(n))
return total
if __name__ == '__main__':
start = time.time()
with Pool(4) as pool:
results = pool.map(cpu_intensive_task, [10_000_000] * 10)
print(f"Temps: {time.time() - start:.2f}s")
À utiliser pour: Calculs intensifs CPU
Comparaison Rapide
Approche I/O Bound CPU Bound Simplicité
Synchrone Lent Lent Simple
Threading Moyen Non Moyen
Async/Await Rapide Non Bon
Multiprocessing Moyen Rapide Complexe
Bonnes Pratiques
Pour I/O (API calls, DB queries): Utilisez async/await
Pour CPU intensif: Utilisez multiprocessing
Évitez threading sauf pour des cas spécifiques
Toujours utiliser des pools pour éviter les memory leaks
Questions pour la Communauté
Quelle approche utilisez-vous dans vos projets?
Avez-vous des patterns async/await recommandés?
Comment gérez-vous le passage de sync à async?
Partagez vos expériences et cas d'usage!
0 Réponses
Aucune réponse pour le moment. Soyez le premier à répondre !