記一次 aiohttp 踩坑
阿新 • • 發佈:2020-12-13
閒來無事準備寫個 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 即可
async with self.session.request(method, url, headers, ...):
# ...
最後附上另一種複用 session 的方法——函式傳參:
async with aiohttp.ClientSession() as session:
# 把 ClientSession 示例傳入協程函式複用
await task(session)
# ...