Как асинхронно сгладить кучу асинхронных генераторов?Python

Программы на Python
Ответить
Anonymous
 Как асинхронно сгладить кучу асинхронных генераторов?

Сообщение Anonymous »

Мне нужно парсить кучу веб-страниц, адреса этих веб-страниц отличаются только номером страницы, поэтому их можно обрабатывать параллельно с помощью aiohttp.
Сейчас я использую асинхронная функция для обработки этих веб-страниц, каждый вызов принимает один адрес в качестве аргумента и возвращает плоский список строк. Я передаю эти URL-адреса сразу, мне нужен плоский список всех строк из каждого вызова функции, меня не волнует порядок этих строк, мне нужна строка, как только она будет получена, независимо от того, есть ли другие Вызовы функций завершены, и я не хочу объединять результаты.
Я просто не могу заставить это работать.
Это Минимальный воспроизводимый пример, иллюстрирующий то же самое проблема:
import asyncio

async def test(n):
await asyncio.sleep(0.5)
for i in range(1, 11):
yield n * i

async def run_test():
ls = []
for i in range(10):
async for j in test(i):
ls.append(j)
return ls

asyncio.run(run_test())

Приведенный выше код выполняется, но не дает ожидаемого результата. Он ждет 5 секунд вместо 0,5 секунды, и каждый раз, когда я запускаю его, результат один и тот же.
Я пробовал это:
async def run_test():
ls = []
for t in asyncio.as_completed([test(i) for i in range(10)]):
for i in await t:
ls.append(i)
return ls

Но это тоже не работает:
TypeError: An asyncio.Future, a coroutine or an awaitable is required

Это тоже не работает:
import asyncio

async def test(n):
await asyncio.sleep(0.5)
for i in range(1, 11):
yield n * i

async def run_test():
ls = []
for x in await asyncio.gather(*(test(i) for i in range(10))):
for j in x:
ls.append(j)
return ls

asyncio.run(run_test())

TypeError: An asyncio.Future, a coroutine or an awaitable is required

Я знаю, что могу сделать это вот так:
import asyncio

async def test(n):
await asyncio.sleep(0.5)
return [n * i for i in range(1, 11)]

async def run_test():
ls = []
for x in asyncio.as_completed([test(i) for i in range(10)]):
ls.extend(await x)
return ls

asyncio.run(run_test())

Но, как я уже говорил выше, я хочу использовать асинхронные генераторы.
Так как же я могу одновременно получать данные от асинхронных генераторов?

Возможно, моя формулировка недостаточно конкретна.
Я имел в виду, что в первом примере каждый раз, когда я запускал run_test()< /code> выводит:
[

0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
2, 4, 6, 8, 10, 12, 14, 16, 18, 20,
3, 6, 9, 12, 15, 18, 21, 24, 27, 30,
4, 8, 12, 16, 20, 24, 28, 32, 36, 40,
5, 10, 15, 20, 25, 30, 35, 40, 45, 50,
6, 12, 18, 24, 30, 36, 42, 48, 54, 60,
7, 14, 21, 28, 35, 42, 49, 56, 63, 70,
8, 16, 24, 32, 40, 48, 56, 64, 72, 80,
9, 18, 27, 36, 45, 54, 63, 72, 81, 90,
]

И это был бы ожидаемый результат, если бы код выполнялся синхронно.
Я думаю, люди предполагали, что мне нужны числа от 0 до 99, Я не знаю, что натолкнуло людей на эту идею.
Конечно, я могу это сделать:
[
10 * i + j
for i in range(10)
for j in range(10)
]

Но зачем мне использовать это вместо list(range(100))?
Дело в том, что выходные данные каждой функции не не имеет значения, я просто хочу собрать записи, как только они станут доступны.
Это немного более сложный пример, он выдает разные выходные данные при каждом запуске, это синхронно, конечно, но это демонстрирует то, чего я хотел добиться асинхронно:
import random

def test(n):
for i in range(1, 11):
yield n * i

def run_test():
gens = [test(i) for i in range(10)]
ls = []
while gens:
gen = random.choice(gens)
try:
ls.append(next(gen))
except StopIteration:
gens.remove(gen)
return ls

run_test()


Подробнее здесь: https://stackoverflow.com/questions/793 ... chronously
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»