Как справиться с ошибкой «Этот цикл событий уже запущен» для вложенной функции в asyncio? - PullRequest
0 голосов
/ 10 мая 2018

Я хочу выполнить очистку веб-страниц с набором категорий, и у каждой категории также есть список URL-адресов.Поэтому я решил вызвать функцию, основанную только на каждой категории в основной функции, и внутри внутренней функции есть неблокирующий вызов.

Так вот код:

def main():
    loop = asyncio.get_event_loop()
    b = loop.create_task(f("p", all_p_list))
    f = loop.create_task(f("f", all_f_list))

    loop.run_until_complete(asyncio.gather(p, f))

Он должен выполнять функцию f одновременно.

Но функция f также должна запускать цикл, поскольку в функции она вызывает функцию одновременно на основе каждого URL.

async def f(category, total): 
    urls = [urls_template[category].format(t) for t in t_list]
    soups_coro = map(parseURL_async, urls)

    loop = asyncio.get_event_loop()
    result = await loop.run_until_complete(asyncio.gather(*soups_coro))

Но после запуска сценария,он получил ошибку This event loop is already running, и я обнаружил, что это потому, что я вызываю loop.run_until_complete() как для внутренних, так и для внешних функций.

Однако, когда я удаляю run_until_complete() и просто вызываю f() вmain(), вызов функции сразу завершился, и он не может ждать завершения внутренней функции.Поэтому неизбежно вызывать цикл в main().Но потом я думаю, что это несовместимо с внутренней функцией, которая также должна вызывать ее.

Как я могу решить проблему и запустить цикл?Оригинальный код все в том же main(), и он работал, но я хочу сделать его чище, если это возможно.

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Преобразовать main() в асинхронную функцию и выполнить ее с помощью loop.run_until_complete().

Когда код имеет только один run_until_complete() - все становится намного проще. В Python 3.7 вы сможете писать только asyncio.run(main())

0 голосов
/ 10 мая 2018

Как справиться с проблемой и запустить цикл?

Цикл уже запущен.Вам не нужно (и не можете) запустить его снова.

result = await loop.run_until_complete(asyncio.gather(*soups_coro))

Вы ожидаете не того.loop.run_until_complete не возвращает то, что вы можете ожидать (a Future);он возвращает результат того, что вы выполняете, до завершения.

Причина, по которой, кажется, ничего не происходит, когда вы вызываете f напрямую, заключается в том, что f является сопрограммой в асинхронном стиле.Как таковой он возвращает будущее, которое должно быть запланировано с помощью цикла событий.Он не выполняется до тех пор, пока не запустится цикл обработки событий.loop.run_until_complete позаботится обо всем этом для вас.

Чтобы завершить свой вопрос, вы должны дождаться asyncio.gather.

async def f(category, total): 
    urls = [urls_template[category].format(t) for t in t_list]
    soups_coro = map(parseURL_async, urls)

    result = await asyncio.gather(*soups_coro)

И вы, вероятно, также хотите включить return result в конце f тоже.

...