Предположим, у нас есть несколько ссылок для загрузки, и каждая ссылка может занять разное количество времени для загрузки. И мне разрешено загружать, используя только 3 соединения. Теперь я хочу убедиться, что я делаю это эффективно, используя asyncio.
Вот что я пытаюсь достичь: в любой момент времени убедитесь, что у меня запущено как минимум 3 загрузки.
Connection 1: 1---------7---9---
Connection 2: 2---4----6-----
Connection 3: 3-----5---8-----
Цифры обозначают ссылки для скачивания, а дефисы - Ожидание загрузки.
Вот код, который я сейчас использую
from random import randint
import asyncio
count = 0
async def download(code, permit_download, no_concurrent, downloading_event):
global count
downloading_event.set()
wait_time = randint(1, 3)
print('downloading {} will take {} second(s)'.format(code, wait_time))
await asyncio.sleep(wait_time) # I/O, context will switch to main function
print('downloaded {}'.format(code))
count -= 1
if count < no_concurrent and not permit_download.is_set():
permit_download.set()
async def main(loop):
global count
permit_download = asyncio.Event()
permit_download.set()
downloading_event = asyncio.Event()
no_concurrent = 3
i = 0
while i < 9:
if permit_download.is_set():
count += 1
if count >= no_concurrent:
permit_download.clear()
loop.create_task(download(i, permit_download, no_concurrent, downloading_event))
await downloading_event.wait() # To force context to switch to download function
downloading_event.clear()
i += 1
else:
await permit_download.wait()
await asyncio.sleep(9)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main(loop))
finally:
loop.close()
И результат такой, как и ожидалось:
downloading 0 will take 2 second(s)
downloading 1 will take 3 second(s)
downloading 2 will take 1 second(s)
downloaded 2
downloading 3 will take 2 second(s)
downloaded 0
downloading 4 will take 3 second(s)
downloaded 1
downloaded 3
downloading 5 will take 2 second(s)
downloading 6 will take 2 second(s)
downloaded 5
downloaded 6
downloaded 4
downloading 7 will take 1 second(s)
downloading 8 will take 1 second(s)
downloaded 7
downloaded 8
Но вот мои вопросы:
В данный момент я просто жду 9 секунд, чтобы основная функция работала до завершения загрузки. Есть ли эффективный способ ожидания завершения последней загрузки перед выходом из основной функции? (Я знаю там asyncio.wait, но мне нужно будет сохранить все ссылки на задачи, чтобы он работал)
Какая хорошая библиотека, которая выполняет такие задачи? Я знаю, что в JavaScript много асинхронных библиотек, но как насчет Python?
Редактировать: 2. Какая хорошая библиотека, которая заботится о распространенных асинхронных шаблонах? (Что-то вроде https://www.npmjs.com/package/async)