请解释“任务已销毁但待处理!”

我正在使用 Python 3.4.2 学习 asyncio,我用它来持续监听 IPC 总线,而 gbulb 监听 DBus。

我创建了一个函数listen_to_ipc_channel_layer,该函数持续侦听 IPC 通道上的传入消息并将消息传递到message_handler.

我也在听 SIGTERM 和 SIGINT。当我向运行您在底部找到的代码的 python 进程发送一个 SIGTERM 时,脚本应该正常终止。

我遇到的问题是以下警告:

got signal 15: exit
Task was destroyed but it is pending!
task: wait_for=>

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().

这不应该CancelledError在while True:循环内触发吗?(因为它不是,但这就是我的理解“调用 cancel() 将向包装的协程抛出 CancelledError”)。

最终loop.stop()被调用,它停止循环而不等待yield from asyncio.sleep(0.1)返回结果甚至整个协程listen_to_ipc_channel_layer。

如果我错了,请纠正我。

我认为我唯一需要做的就是让我的程序等待yield from asyncio.sleep(0.1)返回结果和/或协程以打破 while 循环并完成。

我相信我混淆了很多东西。请帮助我弄清楚这些事情,以便我可以弄清楚如何在没有警告的情况下优雅地关闭事件循环。

已邀请:
拿这段代码:

import asyncio
import signal


async def pending_doom():
await asyncio.sleep(2)
print(">> Cancelling tasks now")
for task in asyncio.Task.all_tasks():
task.cancel()

print(">> Done cancelling tasks")
asyncio.get_event_loop().stop()


def ask_exit():
for task in asyncio.Task.all_tasks():
task.cancel()


async def looping_coro():
print("Executing coroutine")
while True:
try:
await asyncio.sleep(0.25)
except asyncio.CancelledError:
print("Got CancelledError")
break

print("Done waiting")

print("Done executing coroutine")
asyncio.get_event_loop().stop()


def main():
asyncio.async(pending_doom())
asyncio.async(looping_coro())

loop = asyncio.get_event_loop()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, ask_exit)

loop.run_forever()

# I had to manually remove the handlers to
# avoid an exception on BaseEventLoop.__del__
for sig in (signal.SIGINT, signal.SIGTERM):
loop.remove_signal_handler(sig)


if __name__ == '__main__':
main()
通知ask_exit取消任务但不stop循环,在下一个循环中looping_coro()停止它。如果取消它,输出是:

Executing coroutine
Done waiting
Done waiting
Done waiting
Done waiting
^CGot CancelledError
Done executing coroutine
注意在 之后如何立即pending_doom取消和停止循环。如果让它一直运行直到协程从睡眠中醒来,您会看到相同的警告:pending_doom

Executing coroutine
Done waiting
Done waiting
Done waiting
Done waiting
Done waiting
Done waiting
Done waiting
>> Cancelling tasks now
>> Done cancelling tasks
Task was destroyed but it is pending!
task: wait_for=>

要回复问题请先登录注册