2017-09-13 30 views
3

對於下面的代碼使用aiohttp:這個異步aiohttp代碼有什麼問題?

async def send(self, msg, url): 
    async with aiohttp.ClientSession() as session: 
     async with session.post(url, data=msg) as response: 
      self._msg = response.read() 

async def recv(self): 
    return await self._msg 

它的工作原理...大部分的時間,但偶爾(經常,實際上)會導致各種異常 - 通常被截斷的響應,或者連接已經被關閉的除外。

相比之下,下面完美的作品:

async def send(self, msg, url): 
    async with aiohttp.ClientSession() as session: 
     async with session.post(url, data=msg) as response: 
      self._msg = await response.read() 

async def recv(self): 
    return self._msg 

我想知道爲什麼,作爲第二個版本是我的目的,在技術上不正確的,我需要解決它。 (這是不正確的,因爲在讀取響應之前可能會調用recv函數)

+0

「這是不正確的,因爲可能在讀取響應之前調用recv函數」 - 如果它是ca在響應被讀取之前進行填充,那麼在第一個版本中會有什麼「等待」呢? 'self._msg'尚未設置。 – user2357112

+0

準確地說,我只是在發送完成之後纔會調用recv的代碼。但是,這是一個很好的觀點,事實證明,*兩個版本都是根本錯誤的。你能提出一個解決方案,同時仍然保持'發送'和'recv'在概念上分開嗎? – Arafangion

+0

(爲了澄清:雖然我很感激修復,但我想要的真正答案是理解這兩個代碼示例之間的差異) – Arafangion

回答

2

with是一個上下文管理器,它通常在其塊的任何語句之前和之後運行一些代碼。意思是說,你的第一個recv函數很可能等待一個引用已經關閉的連接的未來,或者沿着這些線路。

比方說,你有一些代碼,看起來像這樣:

with open(...) as file: 
    file.read() 

這是做什麼的,大致爲:

file = open(...) 
file.read() 
file.close() 

這是你在做什麼,相當於你第一個示例:

file = open() 
file.close() 
... 
file.read() 
+0

而且這會使未來失效? – Arafangion

+1

我不知道你的意思是「使未來無效」,但基本上,這整個事情不是一個異步問題。這是一個從封閉套接字讀取的問題,或者是'response.read()'中發生的其他事情。 –

+1

更新了答案。 –