什么Task was destroyed but it is pending!
意思
如果目前您的程序已完成一些异步任务,但仍未完成,则会收到此警告。之所以需要此警告,是因为某些正在运行的任务可能无法正确释放某些资源。
有两种常见的解决方法:
- 您可以等待任务自己完成
- 您可以取消任务,等待任务完成
异步和阻止同步操作
让我们来看一下代码:
def shutdown(proto, loop): print("Shutdown of DummyProtocol initialized ...") proto.close() time.sleep(2) # ...time.sleep(2)-这行不会给协程足够的时间。它将冻结所有程序两秒钟。在这段时间内什么都不会发生。
发生这种情况是因为事件循环在您调用的同一进程中运行
time.sleep(2)。您永远不要在异步程序中以这种方式调用长时间运行的同步操作。请阅读此答案以查看异步代码如何工作。
我们如何等待任务完成
让我们尝试修改
shutdown功能。这不是异步函数,您不能
await在其中添加任何内容。要执行一些异步代码,我们需要手动执行:停止当前正在运行的循环(因为它已经在运行),创建一些异步函数来等待任务完成,并传递此函数以在事件循环中执行。
def shutdown(proto, loop): print("Shutdown of DummyProtocol initialized ...") # Set shutdown event: proto.close() # Stop loop: loop.stop() # Find all running tasks: pending = asyncio.Task.all_tasks() # Run loop until tasks done: loop.run_until_complete(asyncio.gather(*pending)) print("Shutdown complete ...")您也可以取消任务并等待它们完成。有关详细信息,请参见此答案。
清理作业地点
我对信号并不陌生,但是您真的需要它来捕获CTRL-
C吗?无论何时
KeyboardInterrupt发生的事件,都会在运行事件循环的地方逐行抛出(在代码中为
loop.run_forever())。我在这里可能是错的,但是处理这种情况的常用方法是将所有清理操作都置于
finally阻塞状态。
例如,您可以看到
aiohttp它是如何进行的:
try: loop.run_forever()except KeyboardInterrupt: # pragma: no branch passfinally: srv.close() loop.run_until_complete(srv.wait_closed()) loop.run_until_complete(app.shutdown()) loop.run_until_complete(handler.finish_connections(shutdown_timeout)) loop.run_until_complete(app.cleanup())loop.close()



