为什么这个异步代码不停止?
Why doesn't this async code stop?
以下代码片段有两个协程,分别用于服务器和客户端。客户端协程具有在 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())
))
如果你运行编码你会看到这样的东西:
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
接收字符串的可能性,但它不会发生,因为已经没有客户端发送它!因为你的事件循环 运行s 直到两个协程都完成它会永远 运行。
这是最简单的解决方法:
@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
请注意,此修复程序仅用于演示问题和一种可能的解决方法。
在现实生活中,我想你会想要做一些不同的事情:可能,为你的协程设置超时,以保证如果 client/server 停止响应它们不会永远卡住。
以下代码片段有两个协程,分别用于服务器和客户端。客户端协程具有在 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())
))
如果你运行编码你会看到这样的东西:
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
接收字符串的可能性,但它不会发生,因为已经没有客户端发送它!因为你的事件循环 运行s 直到两个协程都完成它会永远 运行。
这是最简单的解决方法:
@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
请注意,此修复程序仅用于演示问题和一种可能的解决方法。
在现实生活中,我想你会想要做一些不同的事情:可能,为你的协程设置超时,以保证如果 client/server 停止响应它们不会永远卡住。