Exercice 01 : Simulation de Téléchargements Concurrents
Objectif
Cet exercice a pour but de vous faire utiliser asyncio et asyncio.gather pour simuler le téléchargement de plusieurs fichiers de manière concurrente. Vous pourrez ainsi constater le gain de temps par rapport à une approche synchrone.
Contexte
Imaginez que vous devez télécharger une liste de fichiers depuis des URLs. Chaque téléchargement prend un temps variable. Si vous les téléchargez les uns après les autres (de manière synchrone), le temps total sera la somme de tous les temps de téléchargement.
Avec asyncio, vous pouvez lancer tous les téléchargements "en même temps". Le temps total sera alors approximativement celui du téléchargement le plus long.
Énoncé
-
Créez un nouveau fichier Python nommé
concurrent_downloads.py. -
Définissez une coroutine
download_file.- Elle doit être définie avec
async def. - Elle prend un argument
file_name(une chaîne de caractères). - Elle simule un temps de téléchargement variable. Pour cela :
- Générez un temps de pause aléatoire entre 0.5 et 3.0 secondes en utilisant
random.uniform(0.5, 3.0). - Affichez un message indiquant le début du téléchargement, par exemple :
f"Downloading {file_name}...". - Utilisez
await asyncio.sleep()avec le temps de pause calculé pour simuler l'opération I/O. - Une fois la pause terminée, affichez un message de fin, par exemple :
f"✓ Finished downloading {file_name} in {delay:.2f}s". - La coroutine doit retourner le nom du fichier téléchargé.
- Générez un temps de pause aléatoire entre 0.5 et 3.0 secondes en utilisant
- Elle doit être définie avec
-
Définissez une coroutine principale
main.- Elle doit être définie avec
async def. - Créez une liste de noms de fichiers à "télécharger", par exemple :
["file1.zip", "file2.img", "file3.iso", "file4.pdf"]. - Enregistrez le temps de début avec
time.time(). - Créez une liste de tâches (coroutines) en appelant
download_filepour chaque nom de fichier dans votre liste. - Utilisez
await asyncio.gather(*tasks)pour exécuter toutes les tâches de manière concurrente. - Enregistrez le temps de fin.
- Affichez le temps total d'exécution.
- Elle doit être définie avec
-
Lancez l'exécution.
- À la fin de votre script, utilisez
asyncio.run(main())pour démarrer le programme. - N'oubliez pas d'importer les modules nécessaires :
asyncio,random, ettime.
- À la fin de votre script, utilisez
Résultat Attendu
L'ordre des messages de début et de fin peut varier, mais le schéma général devrait être le suivant : tous les téléchargements commencent presque en même temps, puis se terminent en fonction de leur délai aléatoire. Le temps total doit être proche du délai le plus long (environ 3 secondes), et non de la somme de tous les délais.
Downloading file1.zip...
Downloading file2.img...
Downloading file3.iso...
Downloading file4.pdf...
✓ Finished downloading fileX.xxx in 0.XXs
✓ Finished downloading fileY.yyy in 1.YYs
✓ Finished downloading fileZ.zzz in 2.ZZs
✓ Finished downloading fileW.www in 2.WWs
---
All files downloaded concurrently.
Total time: 2.98 seconds.
Downloaded files: ['file1.zip', 'file2.img', 'file3.iso', 'file4.pdf']
Cliquez ici pour voir un exemple de code de solution
# concurrent_downloads.py
import asyncio
import random
import time
async def download_file(file_name: str) -> str:
"""Coroutine to simulate a file download with a random delay."""
delay = random.uniform(0.5, 3.0)
print(f"Downloading {file_name}...")
await asyncio.sleep(delay)
print(f"✓ Finished downloading {file_name} in {delay:.2f}s")
return file_name
async def main():
"""Main coroutine to run concurrent downloads."""
files_to_download = [
"file1.zip",
"file2.img",
"file3.iso",
"file4.pdf"
]
start_time = time.time()
# Create a list of coroutine objects (tasks)
tasks = [download_file(file) for file in files_to_download]
# Run all tasks concurrently and wait for them to complete
downloaded_files = await asyncio.gather(*tasks)
end_time = time.time()
print("---")
print("All files downloaded concurrently.")
print(f"Total time: {end_time - start_time:.2f} seconds.")
print(f"Downloaded files: {downloaded_files}")
if __name__ == "__main__":
asyncio.run(main())