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

如何在Python中高效实现多进程共享同一变量并行运算?

解决多进程处理大numpy数组时CPU内核态负载过高的问题

你的问题核心是多进程同时访问100GB全局numpy数组时,引发了大量内核态内存操作,导致htop中CPU负载显示为红色。具体原因包括:

  • Joblib默认使用多进程(loky/fork)模式,子进程通过写时复制(COW)共享父进程的数组,但多个进程同时读取超大数组时,会出现缓存颠簸(cache thrashing)——内核需要频繁调度内存页、处理缓存置换,这部分操作属于内核态,占用大量CPU时间。
  • 即使是只读操作,超大数组的跨进程访问也会触发内核层面的内存管理开销,进一步拉高红色负载。

以下是几种优化方案:

方案1:改用多线程Backend

由于numpy的数值运算通常会释放GIL(全局解释器锁),多线程可以共享同一内存空间,避免多进程的COW内存开销和缓存颠簸,大幅降低内核态负载。

修改代码如下:

import numpy as np
from joblib import Parallel, delayed

myVariable = np.load("myFile.npy")
myParameters = np.arange(100)

def myFunction(myParameter):
    return np.mean(myVariable**myParameter)

# 切换为threading backend,替代默认多进程
Parallel(n_jobs=-1, backend="threading")(delayed(myFunction)(p) for p in myParameters)

注意:如果你的numpy依赖MKL/OpenBLAS等多线程线性代数库,需要限制其内部线程数,避免与Joblib的多线程竞争CPU资源。可以通过环境变量设置:

export OMP_NUM_THREADS=1  # 适用于MKL/OpenBLAS

或在Python代码中用threadpoolctl动态控制:

from threadpoolctl import threadpool_limits

with threadpool_limits(limits=1, user_api='blas'):
    Parallel(n_jobs=-1, backend="threading")(delayed(myFunction)(p) for p in myParameters)

方案2:分块并行计算

将大数组拆分为多个小块,每个进程仅处理一块数据,减少单进程的内存访问范围,避免全局数组的跨进程竞争,从而降低内核态的内存调度开销。

以计算均值为例,利用均值的线性可分解特性(总均值=总求和/总元素数),分块计算后汇总结果:

import os
import numpy as np
from joblib import Parallel, delayed

myVariable = np.load("myFile.npy")
myParameters = np.arange(100)
# 根据CPU核心数拆分数组
num_chunks = os.cpu_count()
chunks = np.array_split(myVariable, num_chunks)

def compute_chunk_stats(chunk, param):
    # 计算单块的求和与元素数
    return np.sum(chunk**param), chunk.size

def myFunction(myParameter):
    # 并行处理所有块
    chunk_results = Parallel(n_jobs=-1)(
        delayed(compute_chunk_stats)(chunk, myParameter) for chunk in chunks
    )
    # 汇总结果得到全局均值
    total_sum = sum(res[0] for res in chunk_results)
    total_size = sum(res[1] for res in chunk_results)
    return total_sum / total_size

Parallel(n_jobs=-1)(delayed(myFunction)(p) for p in myParameters)

方案3:使用内存映射加载数组

如果系统物理内存不足(接近或小于100GB),加载整个数组会触发swap,导致大量内核态磁盘IO操作。此时可以用内存映射模式加载数组,按需从磁盘读取数据,减少内存压力:

# 用mmap_mode="r"以只读模式映射数组到内存,不占用全部物理内存
myVariable = np.load("myFile.npy", mmap_mode="r")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 10:35:34