stop(); run_forever() 技巧之所以有效,是因为 stop 的实现方式:
def stop(self):
"""Stop running the event loop.
Every callback scheduled before stop() is called will run.
Callback scheduled after stop() is called won't. However,
those callbacks will run if run() is called again later.
"""
self.call_soon(_raise_stop_error)
def _raise_stop_error(*args):
raise _StopError
因此,下次事件循环运行并执行挂起的回调时,它将调用_raise_stop_error,从而引发_StopError。 run_forever 循环只会在该特定异常时中断:
def run_forever(self):
"""Run until stop() is called."""
if self._running:
raise RuntimeError('Event loop is running.')
self._running = True
try:
while True:
try:
self._run_once()
except _StopError:
break
finally:
self._running = False
因此,通过调度 stop() 然后调用 run_forever,您最终会运行一次事件循环迭代,然后在遇到 _raise_stop_error 回调时停止。您可能还注意到_run_once 是由run_forever 定义和调用的。您可以直接调用它,但如果没有准备好运行的任何回调,有时会阻塞,这可能是不可取的。我认为目前没有更清洁的方法可以做到这一点 - 该答案由asyncio 贡献者 Andrew Svetlov 提供;他可能会知道是否有更好的选择。 :)
一般来说,您的代码看起来很合理,但我认为您不应该一开始就使用这种run_once 方法。这不是确定性的;如果您的列表较长或系统较慢,则可能需要两次以上的额外迭代才能打印所有内容。相反,您应该只发送一个通知接收器关闭的哨兵,然后等待发送和接收协程完成:
import sys
import time
import socket
import asyncio
addr = ('127.0.0.1', 1064)
SENTINEL = b"_DONE_"
# ... (This stuff is the same)
@asyncio.coroutine
def sending(addr, dataiter):
loop = asyncio.get_event_loop()
for d in dataiter:
print("Sending:", d)
sock = socket.socket()
yield from send_close(loop, sock, addr, str(d).encode())
# Send a sentinel
sock = socket.socket()
yield from send_close(loop, sock, addr, SENTINEL)
@asyncio.coroutine
def receiving(addr):
loop = asyncio.get_event_loop()
sock = socket.socket()
try:
sock.setblocking(False)
sock.bind(addr)
sock.listen(5)
while True:
data = yield from accept_recv(loop, sock)
if data == SENTINEL: # Got a sentinel
return
print("Recevied:", data)
finally: sock.close()
def main():
loop = asyncio.get_event_loop()
# add these items to the event loop
recv = asyncio.async(receiving(addr), loop=loop)
send = asyncio.async(sending(addr, range(10)), loop=loop)
loop.run_until_complete(asyncio.wait([recv, send]))
main()
最后,asyncio.async 是将任务添加到事件循环的正确方法。 create_task 是在 Python 3.4.2 中添加的,所以如果你有更早的版本,它将不存在。