Множественные циклы с asyncio

Возможно ли иметь несколько циклов с помощью asyncio? Если ответ положительный, как я могу это сделать? Мой вариант использования: * Я извлекаю URL-адреса из списка веб-сайтов в асинхронном режиме * Для каждого «списка дополнительных URL-адресов» я бы сканировал их в async /

Пример извлечения URL-адресов:

import asyncio
import aiohttp
from suburls import extractsuburls

@asyncio.coroutine
def extracturls(url):
    subtasks = []
    response = yield from aiohttp.request('GET', url)
    suburl_list = yield from response.text()
    for suburl in suburl_list:
        subtasks.append(asyncio.Task(extractsuburls(suburl)))
     loop = asyncio.get_event_loop()
     loop.run_until_complete(asyncio.gather(*subtasks))

 if __name__ == '__main__':
     urls_list = ['http://example1.com', 'http://example2.com']
     for url in url_list: 
          subtasks.append(asyncio.Task(extractsuburls(url)))  
     loop = asyncio.get_event_loop()
     loop.run_until_complete(asyncio.gather(*subtasks))
     loop.close()

Если я выполню этот код, у меня будет ошибка, когда python попытается запустить второй цикл, который говорит, что цикл уже запущен.

P.S: мой модуль «extractsuburls» использует aiohttp для выполнения веб-запроса.

РЕДАКТИРОВАТЬ:

Что ж, я пробовал это решение:

import asyncio
import aiohttp
from suburls import extractsuburls

@asyncio.coroutine
def extracturls( url ):
    subtasks = []
    response = yield from aiohttp.request('GET', url)
    suburl_list = yield from response.text()
    jobs_loop = asyncio.new_event_loop()
    for suburl in suburl_list:
        subtasks.append(asyncio.Task(extractsuburls(suburl)))
     asyncio.new_event_loop(jobs_loop)
     jobs_loop.run_until_complete(asyncio.gather(*subtasks))
     jobs_loop.close()

 if __name__ == '__main__':
     urls_list = ['http://example1.com', 'http://example2.com']
     for url in url_list: 
          subtasks.append(asyncio.Task(extractsuburls(url)))  
     loop = asyncio.get_event_loop()
     loop.run_until_complete(asyncio.gather(*subtasks))
     loop.close()

Но у меня эта ошибка: аргумент цикла должен согласовываться с Future

Любая идея?


person Matt    schedule 10.12.2014    source источник


Ответы (1)


Вам не нужно несколько циклов событий, просто используйте yield from gather(*subtasks) в extracturls() сопрограмме:

import asyncio
import aiohttp
from suburls import extractsuburls

@asyncio.coroutine
def extracturls(url):
    subtasks = []
    response = yield from aiohttp.request('GET', url)
    suburl_list = yield from response.text()
    for suburl in suburl_list:
        subtasks.append(extractsuburls(suburl))
    yield from asyncio.gather(*subtasks)

 if __name__ == '__main__':
     urls_list = ['http://example1.com', 'http://example2.com']
     for url in url_list: 
          subtasks.append(extractsuburls(url))
     loop = asyncio.get_event_loop()
     loop.run_until_complete(asyncio.gather(*subtasks))
     loop.close()

В результате вы ожидаете выполнения подзадач, пока extracturls не завершится.

person Andrew Svetlov    schedule 22.12.2014
comment
Ух ты! Просто идеально. Это именно то, что я хочу. Большое спасибо, Эндрю. - person Matt; 24.12.2014
comment
Еще один вопрос, Эндрю, с помощью этого кода, как я могу установить тайм-аут для каждой задачи? Я хочу убить или вызвать исключение, если задача потратит больше 10 секунд. Является ли это возможным? - person Matt; 05.01.2015
comment
Конечно! Просто оберните сопрограмму задачи в wait_for вызов, например asyncio.Task(asyncio.wait_for(extractsuburls(url), 10.0)) - person Andrew Svetlov; 05.01.2015
comment
Отлично! Большое спасибо, Андрей :) - person Matt; 06.01.2015
comment
asyncio.gather принимает как сопрограммы, так и задачи, поэтому вы можете пропустить два явных asyncio.Task вызова. - person Tom Pohl; 03.06.2015
comment
@TomPohl извините за запоздалую реакцию, но вы правы. Я обновил образец кода, удалив лишние создания задач. - person Andrew Svetlov; 11.09.2016
comment
Это работает. Но я действительно хочу знать, могу ли я использовать 2 петли одновременно - person micfan; 22.10.2016
comment
Вы спрашиваете о двух loop.run_forever() вызовах одновременно в одном потоке? Это невозможно. - person Andrew Svetlov; 23.10.2016