You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多进程运行时如何动态分配剩余可用CPU核心数

环境参数

设备搭载Windows 11系统,4任务多进程运行状态下读取到的CPU规格参数如下:

import psutil
import multiprocessing

print(multiprocessing.cpu_count())
# 12
print(psutil.cpu_count())
# 12
print(psutil.cpu_count(logical=False))
# 6
print(len(psutil.Process().cpu_affinity()))
# 12
业务背景

日常会在该设备上全天同时运行两个独立项目,两个项目运行过程中均会调用multiprocessing实现多进程计算。
此前每个项目处理的DataFrame最大行数为4,因此两个项目同时触发多进程任务时,总进程数最高为8,不会占满CPU资源,原有实现代码如下:

def stackoverflow(stack):
    df = create_dataframe(stack)
    if len(df) == 0:
        pass
    else:
        try:
            max_process = multiprocessing.cpu_count()-1 or 1
            pool = multiprocessing.Pool(max_process)
            list_pool = pool.map(data_event, zip(repeat(stack), df.iterrows()))
        finally:
            pool.close()
            pool.join()

现阶段计划取消DataFrame的行数限制,处理行数范围可从1行到最高1000行不等。如果为每个项目的Pool固定设置5个进程上限,当其中一个项目仅需处理2行数据、另一个需处理8行数据时,后者无法调用空闲CPU资源,会出现效率损耗。
此前曾尝试通过CSV文件交互写入当前占用进程数的方式实现动态分配(该示例仅作思路演示,存在竞态等诸多缺陷完全不可用):两个项目分别读写对应标识的CSV文件,启动多进程前读取对方项目写入的已占用进程数,计算自身可用核心数写入自身标识文件,任务结束后将自身占用数重置为0,示例代码如下:

def stackoverflow(stack):
    df = create_dataframe(stack)
    if len(df) == 0:
        pass
    else:
        another_mp = int(list(csv.reader(open(r'C:\Users\Computer\Desktop\multiprocessing_B.csv')))[0][0])

        free_to_use = 10-another_mp

        with open(r'C:\Users\Computer\Desktop\multiprocessing_A.csv', 'w+', newline='', encoding='UTF-8') as f:
            f.write(free_to_use)

        try:
            max_process = free_to_use
            pool = multiprocessing.Pool(max_process)
            list_pool = pool.map(data_event, zip(repeat(stack), df.iterrows()))
        finally:
            pool.close()
            pool.join()
            with open(r'C:\Users\Computer\Desktop\multiprocessing_A.csv', 'w+', newline='', encoding='UTF-8') as f:
                f.write(0)

另一个项目仅需将代码中读写文件名的A、B标识互换即可实现对应逻辑,但该方案不具备生产可用性。

核心诉求:实现规范的动态进程分配逻辑,当系统中已有X个多进程运行时,新启动的多进程任务可自动使用总CPU核心数减去X后的剩余核心资源。

实现方案

优先选择无额外依赖、无竞态风险的系统负载感知方案,完全不需要在多个项目之间做自定义状态同步:

  • 基于全局CPU负载动态计算可用进程数
    借助psutil采样系统实时CPU使用率,结合总逻辑核心数计算当前可分配的进程数,同时设置合理的上下限,避免进程数为0或过度超配。该方案不限制同时运行的项目数量,后台运行的其他CPU密集型软件也会被纳入负载计算,自动避让资源占用。
    可直接复用的实现代码如下:
    import psutil
    import multiprocessing
    from itertools import repeat
    
    def calc_available_process(min_proc=1, reserved_core=1):
        # 两次采样取平均,规避CPU使用率瞬时波动导致的计算偏差
        psutil.cpu_percent(interval=0.3)
        cpu_usage = psutil.cpu_percent(interval=0.3)
        total_core = multiprocessing.cpu_count()
        # 按空闲占比换算可用核心,预留固定核心给系统基础进程
        free_core = int(total_core * (1 - cpu_usage / 100)) - reserved_core
        # 钳制进程数范围,不低于最小值,不超过总核心数减预留值
        return max(min_proc, min(free_core, total_core - reserved_core))
    
    def stackoverflow(stack):
        df = create_dataframe(stack)
        if len(df) == 0:
            return
        pool = None
        try:
            # 进程数不超过待处理任务行数,避免空进程浪费资源
            max_process = min(calc_available_process(), len(df))
            pool = multiprocessing.Pool(max_process)
            list_pool = pool.map(data_event, zip(repeat(stack), df.iterrows()))
            return list_pool
        finally:
            if pool:
                pool.close()
                pool.join()
    

注意事项

  • 不需要严格要求进程数和空闲核心数1:1匹配,操作系统自带的进程调度器会自动在多个就绪进程之间分配CPU时间片,总进程数不超过逻辑核心数1.5倍时不会产生明显的调度开销。
  • 禁止使用普通文本文件、注册表这类无原子性保证的介质做跨进程状态同步,这类实现天生存在竞态缺陷,并发触发任务时必然出现资源计算错误。
  • 如果需要严格控制所有项目的总进程数上限,可以使用系统原生命名信号量做全局资源计数,相比文件同步方案原子性由操作系统保证,不会出现竞态问题,但会引入少量额外依赖,对绝大多数单机场景而言,上述负载感知方案已经足够稳定可用。

内容的提问来源于stack exchange,提问作者Digital Farmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 14:51:21