如何处理 asyncio 中嵌套函数的 "This event loop is already running" 错误?

How can I deal with "This event loop is already running" error on a nested function in asyncio?

我想用一组类别执行网络抓取,每个类别也有一个 URL 的列表。所以我决定在main函数中只根据每个类别调用一个函数,并且在inner函数内部有一个非阻塞调用。

代码如下:

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(),并在 main() 中调用 f() 时,函数调用立即完成,它不能等待内部函数完成。所以在main()中调用循环是不可避免的。但后来我认为它与内部函数不兼容,内部函数也必须调用它。

如何处理问题和 运行 循环?原始代码都在同一个 main() 中并且有效,但我想尽可能使其更清晰。

How can I deal with the problem and run the loop?

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

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

你等错了。 loop.run_until_complete 没有 return 你可以等待的东西 (a Future);它 return 是你 运行 直到完成的任何结果。

当您直接调用 f 时似乎没有任何反应的原因是 f 是一个 asyncio 风格的协程。因此,它 return 是一个必须用事件循环安排的未来。它不会执行,直到 运行ning 事件循环告诉它执行。 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)

您可能还想在 f 的末尾包含 return result

main()转换为async函数,由loop.run_until_complete()执行。

当代码只有一个时 run_until_complete() -- 一切都变得容易多了。在 Python 3.7 中,您将可以只写 asyncio.run(main())