Проблема реализации асинхронности на генераторах
Пытаюсь разобраться с асинхронностью, хочу попробовать реализовать ее на генераторах. Допустим у меня есть лист ссылок, нужно асинхронно отправить им GET запрос и асинхронно ждать ответа. Сделал первый
import requests
links = ['https://mail.ru', 'https://google.com', 'https://yandex.ru', 'https://habr.com']
def request_links():
result = None
while True:
coroutine = yield result
result = requests.get(link)
result = result.url
g = request_links()
next(g)
for link in links:
print(g.send(link))
И если я правильно понял, в request.get происходит блокирование и все конструкция выполняется синхронно в рамках одного потока. Второй вариант:
from concurrent.futures import ThreadPoolExecutor, as_completed
import requests
links = ['https://mail.ru', 'https://google.com', 'https://habr.com', 'https://yandex.ru']
def corotune(function):
def start(*args, **kwargs):
g = function(*args, **kwargs)
next(g)
return g
return start
@corotune
def request_links():
result = None
while True:
result = yield result
result = requests.get(link)
result = result.url
request_cor = request_links()
with ThreadPoolExecutor(max_workers=6) as executor:
future_list = []
for link in links:
future = executor.submit(request_cor.send, link)
future_list.append(future)
for f in as_completed(future_list):
print(f.result())
Не заработало в итоге, ошибка generator already executing, как я понимаю, объект генератора request_cor у нас один, и повторно запустить его в другом потоке мы не можем. Решить это можно, переносом создания объекта генератора в итерацию прохода ссылок:
with ThreadPoolExecutor(max_workers=6) as executor:
future_list = []
for link in links:
# Создаем новый объект генератора
request_cor = request_links()
future = executor.submit(request_cor.send, link)
future_list.append(future)
for f in as_completed(future_list):
print(f.result())
Но в этом случае, если у нас будет миллион ссылок, то будет создаваться миллион объектов и будет миллион асинхронных объектов и на каждого будет одна задача. Да и сама реализация с использованием ThreadPoolExecutor подразумевает многопоточность. Собственно непонятно как с помощью корутины на генераторах создать асинхронность в рамках одного потока? И возможно ли это сделать. Заранее спасибо