asyncio 抛出运行时错误并忽略异常
asyncio throws runtime error with exception ignored
下面是一个收集 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.await
来 运行 您的所有任务,但您没有检查已完成的任务是否有异常。 await
return 两个序列:一个包含已完成的任务,一个包含待处理的任务 - 您必须查询已完成的任务是否有异常:
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
提供了一个界面来促进这一点 - 只需告诉它什么时候应该 return:
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}")
这是由 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())
当然,第二种解决方案会使你的代码平台特定,所以要小心。
下面是一个收集 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.await
来 运行 您的所有任务,但您没有检查已完成的任务是否有异常。 await
return 两个序列:一个包含已完成的任务,一个包含待处理的任务 - 您必须查询已完成的任务是否有异常:
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
提供了一个界面来促进这一点 - 只需告诉它什么时候应该 return:
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}")
这是由 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())
当然,第二种解决方案会使你的代码平台特定,所以要小心。