如何处理 asyncio 中嵌套函数的“此事件循环已在运行”错误?

Bla*_*ard 5 python python-asyncio

我想使用一组类别执行网页抓取,每个类别还有一个 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))
Run Code Online (Sandbox Code Playgroud)

它应该同时执行该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))
Run Code Online (Sandbox Code Playgroud)

但是运行脚本后,出现错误This event loop is already running,我发现这是因为我loop.run_until_complete()同时调用了内部函数和外部函数。

但是,当我剥离run_until_complete(), 并仅调用f()时main(),函数调用立即完成,并且无法等待内部函数完成。所以不可避免的要调用循环中的main(). 但后来我认为它与内部函数不兼容,内部函数也必须调用它。

我该如何处理这个问题并运行循环?原始代码全部相同main()并且有效,但如果可能的话我想使其更清晰。

dir*_*irn 4

我该如何处理这个问题并运行循环?

循环已经在运行。您不需要(也不能)再次运行它。

result = await loop.run_until_complete(asyncio.gather(*soups_coro))
Run Code Online (Sandbox Code Playgroud)

你在等待错误的事情。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)
Run Code Online (Sandbox Code Playgroud)

您可能还想return result在 的末尾添加f。