2017-12-29 37 views
1

다음 코드 스 니펫에는 서버와 클라이언트에 대해 각각 두 개의 coroutine이 있습니다. 클라이언트 동시 루틴은 while 루프를 10 초 후에 중단하고 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 

확인을 client_coroutine이 성공적으로 완료,하지만이 순간에 무엇을 server_coroutine의 상태? 이 줄에 붙어있는 msg = yield from server_socket.recv_string() 문자열을 server_socket에서 받아들이기를 기다리고 있지만 이미 클라이언트를 보낼 클라이언트가 없기 때문에 발생하지 않습니다! 그리고 두 coroutine이 끝날 때까지 이벤트 루프가 실행되기 때문에 영원히 계속 실행됩니다. 이 수정 문제와이를 해결하기위한 하나의 가능한 방법을 보여 아니라,

@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

감사합니다. Mikhail은 많은 coroutine이있는 대규모 응용 프로그램을위한 방법으로 이벤트 루프가 대기/멈추고있는 곳입니까? –

+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) 코 루틴 또는 훌륭한 제 3 자 [async-timeout]을 사용하는 것입니다. (https://pypi.python.org/pypi/async_timeout) 컨텍스트 관리자 (내부에 여러 개의 작업을 배치 할 수 있음). –