我正在用Python 3.4.2学习asyncio,我用它在IPC总线上连续监听,而gbulb在DBU上监听.
我创建了一个函数listen_to_ipc_channel_layer
,它持续监听IPC通道上的传入消息,并将消息传递给message_handler
.
我也在听SIGTERM和SIGINT.当我向运行您在底部找到的代码的python进程发送SIGTERM时,脚本应该会优雅地终止.
我遇到的问题是以下警告:
got signal 15: exit
Task was destroyed but it is pending!
task: <Task pending coro=<listen_to_ipc_channel_layer() running at /opt/mainloop-test.py:23> wait_for=<Future cancelled>>
Process finished with exit code 0
…使用以下代码:
import asyncio
import gbulb
import signal
import asgi_ipc as asgi
def main():
asyncio.async(listen_to_ipc_channel_layer())
loop = asyncio.get_event_loop()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, ask_exit)
# Start listening on the Linux IPC bus for incoming messages
loop.run_forever()
loop.close()
@asyncio.coroutine
def listen_to_ipc_channel_layer():
"""Listens to the Linux IPC bus for messages"""
while True:
message_handler(message=channel_layer.receive(["my_channel"]))
try:
yield from asyncio.sleep(0.1)
except asyncio.CancelledError:
break
def ask_exit():
loop = asyncio.get_event_loop()
for task in asyncio.Task.all_tasks():
task.cancel()
loop.stop()
if __name__ == "__main__":
gbulb.install()
# Connect to the IPC bus
channel_layer = asgi.IPCChannelLayer(prefix="my_channel")
main()
我仍然对asyncio知之甚少,但我想我知道发生了什么.在等待yield from asyncio.sleep(0.1)
的过程中,信号处理器捕捉到SIGTERM,并在该过程中调用task.cancel()
.
这不应该触发while True:
循环中的CancelledError
吗?(因为不是,但这就是我对"Calling cancel() will throw a CancelledError to the wrapped coroutine"的理解).
最终调用loop.stop()
,它停止循环,而不等待yield from asyncio.sleep(0.1)
返回结果,甚至不等待整个协程listen_to_ipc_channel_layer
.
如果我错了,请纠正我.
我认为我需要做的唯一一件事就是让我的程序等待yield from asyncio.sleep(0.1)
返回结果and/or协同程序,以打破while循环并完成.
我相信我混淆了很多事情.请帮我弄清楚这些事情,这样我就可以想出如何在没有警告的情况下优雅地关闭事件循环.