mirror of
https://github.com/ThearchyHelios/AgentLab.git
synced 2026-11-15 09:11:59 +00:00
29 lines
1.5 KiB
Python
29 lines
1.5 KiB
Python
"""进程里「发出去就不管」的后台任务(推送通知、评测收尾的清理):留着引用免得被回收,测试和关停时等它们做完。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from typing import Any
|
|
|
|
|
|
async def drain(tasks: set[asyncio.Future[Any]]) -> None:
|
|
"""等 tasks 里本事件循环上的任务都做完。
|
|
|
|
已经做完的直接从集合里摘掉,不等它们自己的 discard 回调:done 回调排在任务所在的事件循环上,那个循环要是已经不转了(测试里
|
|
每个测试一个事件循环,前一个测试末尾刚做完的推送)回调就永远不跑、任务一直留在集合里。以前的写法 `while tasks: await
|
|
gather(*tasks)` 碰上这种集合,gather 拿到的全是做完了的、立刻返回,await 不让出事件循环,就在这里空转——CPU 打满、整个
|
|
进程卡死(PostgreSQL 全量里 test_personal_apps 收尾时出现过)。别的事件循环上还没做完的等不到(不在这个循环上),不等;
|
|
那个循环已经关了的一并摘掉。"""
|
|
loop = asyncio.get_running_loop()
|
|
while True:
|
|
for task in list(tasks):
|
|
if task.done() or (task.get_loop() is not loop and task.get_loop().is_closed()):
|
|
tasks.discard(task)
|
|
mine = [task for task in tasks if task.get_loop() is loop]
|
|
if not mine:
|
|
return
|
|
await asyncio.gather(*mine, return_exceptions=True)
|
|
|
|
|
|
__all__ = ["drain"]
|