【问题标题】:asyncio throws runtime error with exception ignoredasyncio 抛出运行时错误并忽略异常
【发布时间】:2021-06-24 22:17:18
【问题描述】:

下面是一个收集 URL 长度的简单程序。

import aiohttp
import asyncio
from time import perf_counter


URLS = ['http://www.cnn.com', 'http://www.huffpost.com', 'http://europe.wsj.com',
        'http://www.bbc.co.uk', 'http://failfailfail.com']

async def async_load_url(url, session):
    try:
        async with session.get(url) as resp:
            content = await resp.read()
        print(f"{url!r} is {len(content)} bytes")
    except IOError:
        print(f"failed to load {url}")        

async def main():

    async with aiohttp.ClientSession() as session:
        tasks = [async_load_url(url, session) for url in URLS]
        await asyncio.wait(tasks)

if __name__ == "__main__":
    start = perf_counter()
    asyncio.run(main())
    elapsed = perf_counter() - start
    print(f"\nTook {elapsed} seconds")

为什么以下代码会因运行时错误而失败,并且在 python 3.9 中忽略了异常?如何解决?

Traceback 是:RuntimeError: Event loop is closed 特别是 Exception ignored in: <function _ProactorBasePipeTransport.__del__ at 0x000001F8A7A713A0>

【问题讨论】:

  • 是运行时错误吗?或者这是一个警告?它可能希望你对asyncio.wait 返回的任务做点什么。
  • 请更新问题以包含回溯。
  • 看起来您使用的是 Windows,在这种情况下,这是 aiohttp 中的一个已知问题 github.com/aio-libs/aiohttp/issues/4324

标签: python-3.x python-asyncio aiohttp


【解决方案1】:

这是由 Windows 上的 aiohttp 中的一个已知问题引起的,有关详细信息,请查看 https://github.com/aio-libs/aiohttp/issues/4324 的错误

有一些技巧可以消除此错误。第一种方法是获取事件循环并调用run_until_complete 而不是asyncio.run(main()),如下所示:

asyncio.get_event_loop().run_until_complete(main())

或者,在调用asyncio.run(main()) 之前将事件循环策略更改为WindowsSelectorEventLoopPolicy 也可以工作,因为使用WindowsProtractorEventLoopPolicy 时似乎会出现问题。

asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(main())

当然,第二种解决方案会使您的代码平台特定,所以要小心。

【讨论】:

    【解决方案2】:

    您正在使用asyncio.await 运行所有任务,但您没有检查已完成的任务是否存在异常。 await 返回两个序列:一个是已完成的任务,一个是待处理的任务 - 您必须查询已完成的任务是否有异常:

    async def main():
        async with aiohttp.ClientSession() as session:
            tasks = [asyncio.task(async_load_url(url, session), name=url) for url in URLS]
            done, pending = await asyncio.wait(tasks)
            for task in done:
                try:
                    task.exception() # in task execption is re-raised
                except Exception as exc:
                    print (f"Exception loading url {task.name}:\n {exc}")
    
    

    如果这是一个漫长的过程,并且您想在异常发生时对其进行处理,asyncio.wait 提供了一个接口来促进这一点 - 只需告诉它何时应该返回:

            
        async def main():
        async with aiohttp.ClientSession() as session:
            tasks = [asyncio.task(async_load_url(url, session), name=url) for url in URLS]
            while tasks:
                done, tasks = await asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
                for task in done:
                    try:
                        task.exception() # in task execption is re-raised
                    except Exception as exc:
                        print (f"Exception loading url {task.name}:\n {exc}")
    
    

    【讨论】:

      猜你喜欢
      • 2010-09-14
      • 2012-05-24
      • 1970-01-01
      • 2022-06-29
      • 1970-01-01
      • 1970-01-01
      • 2014-06-10
      • 2012-08-21
      • 2015-06-03
      相关资源
      最近更新 更多