import asyncio # асинхронная работа
import time # измерение времени
async def download(url, sem, idx, log): # загрузка одной ссылки
async with sem: # ограничение числа одновременных задач
log.append(f"START {idx}: {url}") # записать старт
await asyncio.sleep(1) # имитация скачивания
log.append(f"END {idx}: {url}") # записать конец
return f"file_{idx}_downloaded" # вернуть результат
async def download_all(urls, k): # скачать всё асинхронно
sem = asyncio.Semaphore(k) # лимит параллелизма
log = [] # список лога
tasks = [asyncio.create_task(download(url, sem, i + 1, log)) for i, url in enumerate(urls)] # создать задачи
results = await asyncio.gather(*tasks) # дождаться всех задач
return results, log # вернуть результаты и лог
def download_all_sync(urls): # скачать всё синхронно
results = [] # список результатов
for i, url in enumerate(urls, 1): # пройти по всем ссылкам
time.sleep(1) # блокирующее ожидание
results.append(f"file_{i}_downloaded") # сохранить результат
return results # вернуть список
def main(): # главная функция
urls = ["file1", "file2", "file3", "file4", "file5", "file6"] # список ссылок
k = 3 # максимум одновременных задач
t1 = time.perf_counter() # старт синхронного таймера
sync_results = download_all_sync(urls) # синхронное скачивание
sync_time = time.perf_counter() - t1 # время синхронного варианта
t2 = time.perf_counter() # старт асинхронного таймера
async_results, log = asyncio.run(download_all(urls, k)) # асинхронное скачивание
async_time = time.perf_counter() - t2 # время асинхронного варианта
print("SYNC:", sync_results, f"{sync_time:.2f} sec") # вывод синхронного результата
print("ASYNC:", async_results, f"{async_time:.2f} sec") # вывод асинхронного результата
print("LOG:") # заголовок лога
for line in log: # перебор строк лога
print(line) # печать строки
if __name__ == "__main__": # запуск только при прямом старте файла
main() # вызов главной функции