1、先上bug代码:
import asyncio
import aiohttp
urls = [
"https://tenfei03.cfp.cn/creative/vcg/800/new/VCG211224199769.jpg",
"https://alifei03.cfp.cn/creative/vcg/800/new/VCG211226914371.jpg",
"https://tenfei02.cfp.cn/creative/vcg/800/new/VCG211188068441.jpg"
]
async def aiodownload(url):
name = url.rsplit("/", 1)[1] # 从右边切,切一次,得到[1]位置的内容
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
# 返回请求,写入数据
with open(name, mode="wb") as f: # 创建文件
f.write(await resp.content.read()) # 读取内容是异步的需要在前面加上await content读图片
print(name,"下载成功")
async def main():
tasks = []
for url in urls:
tasks.append(asyncio.create_task(aiodownload(url)))
await asyncio.wait(tasks)
if __name__ == '__main__':
asyncio.run(main())
2、run后会报出错误(RuntimeError: Event loop is closed):
3、解决方法:在调用 run 函数前,替换默认的 ProactorEventLoop 为 SelectorEventLoop
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(main())
4、原因分析:
像 aiohttp 这类第三方协程库都是依赖于标准库 asyncio 的,而 asyncio 对 Windows 的支持本来就不好。Python3.8 后默认 Windows 系统上的事件循环采用 ProactorEventLoop (仅用于 Windows )这篇文档描述了其在 Windows 下的缺陷:https://docs.python.org/zh-cn/3/library/asyncio-platforms.html#windows
引发异常的函数是 _ProactorBasePipeTransport.__del__ ,所以 aiohttp 铁定使用了 _ProactorBasePipeTransport,并且在程序退出释放内存时自动调用了其__del__ 方法