2017-08-17 8 views
0

websocketエンドポイント経由で利用できるPythonサーバーがあります。 接続の処理中は、バックエンドサービスと通信します。この通信は非同期であり、websocketのsend()メソッドを起動することがあります。Python websockets get stuck

単一のクライアントがサービスされると、正常に動作しているようです。ただし、複数のクライアントが並行して処理される場合、接続を処理するルーチンの中には時折スタックされることがあります。より正確には、recv()メソッドではブロックされているようです。

明らか
class MinimalConversation(object): 

    def __init__(self, ws, worker_sck, messages, should_continue_conversation, should_continue_listen): 
     self.ws = ws 
     self.messages = messages 
     self.worker_sck = worker_sck 
     self.should_continue_conversation = should_continue_conversation 
     self.should_continue_listen = should_continue_listen 

async def run_conversation(self): 
     serving_future = asyncio.ensure_future(self.serve_connection()) 
     listening_future = asyncio.ensure_future(self.handle_worker()) 
     await asyncio.wait([serving_future, listening_future], return_when=asyncio.ALL_COMPLETED) 

async def serve_connection(self): 
     while self.should_continue_conversation(): 
      await self.ws.recv() 
      logger.debug("Message received") 
      self.sleep_randomly(10, 5) 
      await self.worker_sck.send(b"Dummy") 

async def handle_worker(self): 
     while self.should_continue_listen(): 
      self.sleep_randomly(50, 40) 
      await self.worker_sck.recv() 
      await self.ws.send(self.messages.pop()) 

def sleep_randomly(self, mean, dev): 
     delta = random.randint(1, dev)/1000 
     if random.random() < .5: 
      delta *= -1 
     time.sleep(mean/1000 + delta) 

実際のコードは何とか複雑で、問題は、私が説明しているよりもやや複雑で、それにもかかわらず、私は彼がWebSocketを使用する方法をスケッチコードの最低限の骨格を提供します実際のコードでは、私はランダムな間隔でスリープしておらず、メッセージのリストを使用しませんが、これは私がウェブソケットを扱う方法を描いています。実際の設定では、websocket経由で送信されるエラーが発生する可能性がありますので、理論的に並行send()が発生する可能性がありますが、このような状況に遭遇したことはありません。

コードは、パラメータとしてwebsockets.serve()に渡され、MinimalConversationオブジェクトを初期化し、run_conversation()メソッドを呼び出すハンドラ関数から実行されます。

私の質問は以下のとおりです。

  • はWebSocketをのような使用とは根本的に間違って何かがありますか?
  • send()メソッドの同時呼び出しは危険ですか?
  • websocketとasyncioの使用に関するいくつかの良い方法を提案できますか?

タクyou。

答えて

1

recv機能は、メッセージが受信された場合にのみバックもたらし、お互いからのメッセージを待っている2つの接続があるようですので、似たような状況があるかもしれない「デッドロック」するとき、彼らはお互いのメッセージを待っているし、することができます何も送っていない。たぶん、全体のアルゴリズムをより安全に再考しようとする必要があります。

さらに、デバッグ出力を追加して実際に何が起こっているかを確認してください。

send()メソッドの同時呼び出しは危険ですか?

同じスレッドであっても、独立してスケジュールされたコルーチンであれば、並列送信は問題ありません。しかし、コルーチンスケジューリングの順序は明らかではないかもしれないので、recvのどちらの呼び出しが最初にメッセージを受け取るかを決定するので、同じ接続上の "並列" recvに注意してください。

websocketとasyncioの使用に関するいくつかの良い方法を提案できますか?

私の経験上、最も簡単な方法は、接続が閉じられるまで接続でrecvを繰り返し呼び出す着信接続用の専用タスクを作成することです。接続をどこかに保存してfinallyブロックで削除すると、他のコルーチンから何かを送ることができます。