为什么这个异步代码不会停止?

时间:2017-12-29 13:49:24

标签: python python-asyncio coroutine pyzmq

以下代码段有两个用于服务器和客户端的协同程序。客户端协程有一个逻辑可以在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 个答案:

答案 0 :(得分: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重新接收字符串的可能性,但它不会发生,因为已经没有客户端发送它!而且,由于你的事件循环一直运行直到两个协同程序完成,它将永远运行。

这是最简单的解决方法:

@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

请注意,此修复程序仅用于演示问题和解决问题的一种可能方法。

在现实生活中,我认为你会想要做一些不同的事情:可能会为你的协同程序设置超时,以保证在客户端/服务器停止响应时它们不会永远停留。