2017-01-30 25 views
2

コルーチンのタイムアウトをどのようにして停止できますか?Pythonコルーチンのタイムアウト

asyncio.wait_for()がなぜ機能しないのですか? 私は(Telnetクライアントの私の実装を作ることを計画)のコードのように平和を持っている:

def expect(self, pattern, timeout=20): 
    if type(pattern) == str: 
     pattern = pattern.encode('ascii', 'ignore')   
    return self.loop.run_until_complete(asyncio.wait_for(self.asyncxpect(pattern), timeout)) 

async def asyncxpect(self, pattern): #receives data in a cumulative way until match is found 
    regexp = re.compile(b'(?P<payload>[\s\S]*)(?P<pattern>%s)' %pattern) 
    self.buffer = b'' 
    while True: 
     # add timeout 
     # add exception handling for unexpectedly closed connections 
     data = await self.loop.sock_recv(self.sock, 10000) 
     self.buffer += data 
     m = re.match(regexp, self.buffer) 
     if m: 
      payload = m.group('payload') 
      match = m.group('pattern') 
      return payload, match 

私は(待つ文で)いくつかの点で、このコードを思ったようにはイベントループに制御を返します。私は受け取るべきデータがなくなったらそれが起こるべきだと思った。 イベントループに制御がある場合、タイムアウトで停止することがあります。

しかし、サーバが有用なもの(一致したもの)を送信しなければ、私のコードは待ち時間のちょうどこのループに入り込みます。

私はtime.sleep(n)のようなブロッキングステートメントを使用していないので、この問題Python asyncio force timeoutとは異なると思います。サーバは、ファイルの終わりを示す、空のByteArray(b'')を返しsock_recv接続を閉じ

Here is my code

+0

私はtime.sleep(n)のようなブロッキングステートメントを使用していないので、この問題 "Python asyncio force timeout"とは異なると思います。 –

+0

コメントで示されているように、これは実際には非同期関数でブロッキングコールを使用する問題である他の質問とはかなり異なっています。詳細は私の答えを見てください。 – user4815162342

答えて

0

。あなたはその条件条件を処理しないので、あなたのコードは、同じバッファを処理する無限ループに詰まることになります。 data = await loop.sock_recv(...)行の後に...

if data == b'': 
    break 

:ようなものを追加し、それを修正するには

しかし、上記の理由で、なぜwait_forが不正なコルーチンをキャンセルできないのか説明できません。問題はawaitが時々表示されるので、「イベントループへの制御を渡す」という意味ではないということです。これは、オブジェクトが値準備ができていないことをオブジェクトが示している場合は、がイベントループに制御を与える、提供された待機可能オブジェクトからの要求値を意味します。 ifの後の部分は重要です。オブジェクトの場合はに値が用意されていれば、この値はすぐにイベントループを延期することなく使用されます。つまり、awaitは、イベントループが実行されることを保証しません。

例えば、以下のコルーチンが完全に遮断イベントループと何もから成るその内側のループにもかかわらず、これまでに実行されているから、他のコルーチンを防止するが、待っている:あなたの例では

async def busy_loop(): 
    while True: 
     await noop() 

async def noop(): 
    pass 

、以来、ファイルの終わりになってもソケットは全くブロックされず、コルーチンは決して中断されず、(上記のバグと併せて)あなたのコルーチンは決して終了しません。

他のタスクが実行できるようにするには、await asyncio.sleep(0)をループに追加します。これは大部分のコードでは必要ではありません。IOデータを要求するとすぐに待ち状態になり、イベントループが開始されます。コードがスタックされたEOF処理バグとの組み合わせでのみ発生します。

関連する問題