是否可以检查 asyncio.Task 是否已阻塞或就绪?

问题描述 投票:0回答:1

我正在开发一个用 Python 编写的类似 make 的系统,我希望能够限制用于并行构建的内核数量,类似于 GNU make 支持的

-j
/
--jobs
选项。每个构建“作业”都是一个
asyncio.Task
,并且可能会产生子进程作为其工作的一部分。我要求作业仅通过我提供的函数生成外部进程,因此我可以跟踪在任何给定时间运行的外部进程数量,并相应地从使用中的核心计数中添加/减去(目前我天真地假设每个外部进程是单线程的)并在必要时使用信号量阻止等待更多核心。

除了外部进程之外,还有一个 CPython 本身的问题。构建作业可能会异步启动子进程,在这种情况下,需要 2 个核心,一个用于 CPython,一个用于外部作业。但是,如果构建作业启动一个子进程并等待它,并且没有其他构建作业正在运行(所有其他

asyncio.Task
都被阻止),那么只需要 1 个核心,因为整个 CPython 被阻止。

换句话说,由于即使使用

asyncio.Task
,CPython 解释器也是单线程的,我认为 CPython 本身应该只算作消耗 0 个核心(所有任务被阻止)或 1 个核心(至少 1 个任务未被阻止)。然而,这需要能够从当前任务中查询当前是否有任何其他任务可运行;如果没有,并且我们将阻止等待进程完成,我们应该暂时减少正在使用的核心计数,因为 CPython 即将休眠,然后我们可以在任何任务恢复运行时立即将其增加回来。

这可以通过 asyncio 实现吗?我看到我可以查询任务是否完成,但我没有看到可运行的概念。我需要自己的事件循环实现吗?我该怎么做?

python async-await python-asyncio event-loop
1个回答
0
投票

我认为如果没有自定义事件循环或一些猴子修补恶作剧,很难而且几乎不可能实现。

请记住,一个任务可以等待另一个内部任务,例如

sleep(0)
。这是否意味着它要停止了?理论上它正在等待任务。实际上它休眠了 0 秒。您可以创建一个丑陋的计时器 0.00001 秒并检查任务是否恢复,但它很丑陋。

您要寻找的是修补选择器并强制选择器事件循环,如果选择接收的时间大于 0,则意味着它即将休眠(禁止传入的网络活动或其他类型),或者完全创建一个新的事件循环,主要重构在

_run_once()
部分。

我认为内省

all_tasks()
是不可能的,因为它将需要大量丑陋的跳转到内部,并且可能会导致同样需要猴子修补,以及为任务构建依赖树。

总而言之,在盒子之外进行处理并内省 Python 程序的 CPU 使用情况可能会更容易,或者只是让操作系统通过启动额外的进程来调度和选择内核,以防万一。

如果您愿意,我可能可以尝试猴子修补选择器事件循环。应该不会太难吧...

© www.soinside.com 2019 - 2024. All rights reserved.