2017-12-29 19 views
1

次のコードスニペットには、サーバーとクライアントの2つのコルーチンがあります。クライアントコルーチンには、10秒後にwhileループを切断するロジックがあり、15秒後にサーバーが停止する必要があります。なぜこの非同期コードが停止しないのですか?

スクリプトを実行すると、これは停止しません。理想的には、15秒後に停止する必要がありますが、これは起こっていません。あなたは、コードを実行した場合

import asyncio 
import time 
import zmq 
import zmq.asyncio 

zmq.asyncio.install() 

ctx = zmq.asyncio.Context() 


server_socket = ctx.socket(zmq.REP) 
client_socket = ctx.socket(zmq.REQ) 

server_socket.bind("tcp://127.0.0.1:8899") 
client_socket.connect("tcp://127.0.0.1:8899") 

t0 = time.time() 


@asyncio.coroutine 
def server_coroutine(): 

    while True: 
     msg = yield from server_socket.recv_string() 
     print(msg) 
     msg = "Server:: {}".format(msg) 
     yield from server_socket.send_string(msg) 
     t1 = time.time() 
     elapsed_time = t1 - t0 
     # print('elapsed time is {}'.format(elapsed_time)) 
     if elapsed_time > 15: 
      print("Breaking Server loop") 
      break 

@asyncio.coroutine 
def client_coroutine(): 
    counter = 0 
    while True: 
     yield from asyncio.sleep(2) 
     msg = 'Message: {}'.format(counter) 
     yield from client_socket.send_string(msg) 
     res = yield from client_socket.recv_string() 
     print(res) 
     t1 = time.time() 
     elapsed_time = t1 - t0 
     print('elapsed time is {}'.format(elapsed_time)) 
     if elapsed_time > 10: 
      print("Breaking Client loop") 
      break 
     counter += 1 


if __name__ == '__main__': 

    loop = asyncio.get_event_loop() 

    loop.run_until_complete(asyncio.gather(
     asyncio.ensure_future(server_coroutine()), 
     asyncio.ensure_future(client_coroutine()) 
    )) 

答えて

1

あなたはこのようなものが表示されます:

Server:: Message: 4 
elapsed time is 10.022311687469482 
Breaking Client loop 

[OK]を、client_coroutineは正常に終了しましたが、この時点で何server_coroutineの状態?これはmsg = yield from server_socket.recv_string()の文字列をserver_socketから受け取る可能性を待っていますが、すでにクライアントを送信していないので、それは起こりません!そして、両方のコルーチンが実行されるまでイベントループが実行されるので、それは永遠に実行されます。この修正プログラムは、問題とそれを解決する1つの可能な方法を実証するだけで、

@asyncio.coroutine 
def server_coroutine(): 
    while True: 
     msg = yield from server_socket.recv_string() 
     if msg == 'CLOSE': # LOOK HERE 1 
      break 
     print(msg) 
     msg = "Server:: {}".format(msg) 
     yield from server_socket.send_string(msg) 
     t1 = time.time() 
     elapsed_time = t1 - t0 
     # print('elapsed time is {}'.format(elapsed_time)) 
     if elapsed_time > 15: 
      print("Breaking Server loop") 
      break 

@asyncio.coroutine 
def client_coroutine(): 
    counter = 0 
    while True: 
     yield from asyncio.sleep(2) 
     msg = 'Message: {}'.format(counter) 
     yield from client_socket.send_string(msg) 
     res = yield from client_socket.recv_string() 
     print(res) 
     t1 = time.time() 
     elapsed_time = t1 - t0 
     print('elapsed time is {}'.format(elapsed_time)) 
     if elapsed_time > 10: 
      print("Breaking Client loop") 
      yield from client_socket.send_string('CLOSE') # LOOK HERE 2 
      break 
     counter += 1 

注:

は、ここで最も簡単な修正です。私はあなたが別の何かをしたいと思う実際の生活の中で

は:おそらく、クライアント/サーバーが応答を停止した場合、彼らは永遠に立ち往生していないことを保証するためにあなたにコルーチンをタイムアウトを設定します。

+0

ありがとう、ミハイルは、多くのコルーチンがある大規模なアプリケーションのために、イベントループが待機しているか停止していますか? –

+0

は@bruce_wayne常にあなたの操作のためのタイムアウトを持つべきです。 asyncioでは大きな問題ではありません。タイムアウトしたタスクは[標準メカニズムで取り消す]ことができます(https://stackoverflow.com/a/43810272/1113207)。これを達成する最も簡単な方法は、[asyncio.wait_for](https://docs.python.org/3/library/asyncio-task.html#asyncio.wait_for)コルーチンまたは素晴らしいサードパーティの[async-timeout] (https://pypi.python.org/pypi/async_timeout)コンテキストマネージャ(あなたはその中に複数の操作を配置することができます)。 –

関連する問題