记一次 aiohttp 踩坑
闲来无事准备写个 aio 版文件下载器,中间没有碰到什么问题,但调试的时候发现发送多次请求,发一次之后就会报 Connector is closed 异常。
这里写了个 Downloader 类,实现生产者/消费者模型的下载器:
class Downloader(object):
def __init__(self, session=None, maxsize=120):
self.url_queue = asyncio.Queue(maxsize)
if session:
self.session = session
else:
self.session = asyncio.get_event_loop().run_until_complete(self.create_session())
# 把 session 包在协程里返回,如果直接创建 session 会报个 warning
async def create_session(self):
return aiohttp.ClientSession()
注意这里我们通过asyncio.get_event_loop().run_until_complete(self.create_session())获取到了 session,发请求的时候直接用 self.session.get 等方法即可,问题也是出现在这里,于是调了(猜了)很多次终于发现了问题代码:
# with 会在代码执行完后关闭 session
async with self.session as session:
async with session.request(method, url, headers, ...):
# ...
这里习惯性的用了with语句,当这个块执行一次之后 session 就被关闭了,所以导致了之前提到的问题。
正确的写法是:
# 直接用在构造函数里创建的 session 即可
async with self.session.request(method, url, headers, ...):
# ...
最后附上另一种复用 session 的方法——函数传参:
async with aiohttp.ClientSession() as session:
# 把 ClientSession 示例传入协程函数复用
await task(session)
# ...

浙公网安备 33010602011771号