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

Python多进程池运行随时间变慢的排查与解决请求

问题描述

我们尝试通过多进程池运行多个模拟任务以缩短总运行时间,替代串行执行。运行初期CPU和GPU利用率高达95-100%,但随时间推移降至2-4%。

核心代码

import multiprocessing
import main_mp

def run_sim(process_num, input_list, gpu_device_list):
    """
    multiprocess target function
    :param input_list: list of input files tasks
    :param process_num: process number
    :param gpu_device_list: gpu_device ids for each task
    """
    start_time = time.time()
    try:
        print(f"Process number: {process_num} starting")
        main_mp.run_mp_simulation_flow_dist(input_list, gpu_device_list)
        status = "completed"
    except Exception as e:
        print(f"Process number: {process_num} failed")
        status = "failed"
    finally:
        end_time = time.time()
        elapsed_time = end_time - start_time
        log_process_status(process_num, status, elapsed_time)


if __name__ == '__main__':

    # multi-process parameters
    multi_processes_number = int(multiprocessing.cpu_count())
    gpu_workers = get_cuda_device()
    
    # get file list and split it to tasks
    tuple_file_list = get_files(path)
    data_list, worker_num = split_data(tuple_file_list, args.process_num)
    
    # assign gpus to each task to balance the overall workload
    data_list_sorted = sb.run_sort(data_list, len(gpu_workers))

    total_runtime = 0
    total_start_time = time.time()

    multiprocessing.freeze_support()

    # run simulation flow
    with multiprocessing.Pool(worker_num) as pool:
        run_times.append(pool.starmap(run_sim,[(i, data_list_sorted[i][0], data_list_sorted[i][1])
                                                for i in range(worker_num)]))

    # close all worker processes
    pool.close()
    pool.join()

    total_end_time = time.time()
    total_runtime = total_end_time - total_start_time

    save_log(in_file_list, multi_processes_number, gpu_workers)
    print("multi-process flow completed in ", round(total_runtime/60, 3), " minutes")

环境详情

  • Python 3.12.4
  • AWS g6.24xlarge实例(96 vCPU、4块NVIDIA L4 GPU)
  • CUDA 12.3
  • Ubuntu Server 24.04

任务特性

模拟任务由run_mp_simulation_flow_dist()调用,该函数基于OpenMP和CUDA实现,但无法控制其资源分配逻辑。每个进程的模拟任务包含多个串行子任务,子任务完成后会写入磁盘,且子任务通过OpenMP和CUDA加速。

已尝试的调试操作

  • 将进程数从96改为40
  • 在Ubuntu机器上设置set_start_method为spawn
  • 设置max_tasks_per_child为1
  • 相同硬件的Windows Server 2022机器上运行无性能下降现象

进程状态观察

执行ps afx命令显示进程带有--multiprocessing-fork参数,性能下降时多数进程处于R1状态,磁盘写入减少。

疑问

  1. 是否是进程挂起占用资源导致连锁反应?
  2. Ubuntu与Windows的核心差异是什么?
  3. 如何解决该性能下降问题?

解决方案分析

1. 进程挂起与连锁反应的可能性

是,大概率存在进程挂起或阻塞引发的连锁影响。当部分进程因资源竞争、锁等待或磁盘IO阻塞时,会占用CPU调度资源但无法有效执行,导致其他进程的调度优先级被抢占,整体利用率暴跌。R1状态(可运行但等待CPU)说明进程处于就绪队列但得不到调度,结合磁盘写入减少,可能是子任务完成后的磁盘IO操作出现阻塞,或者OpenMP/CUDA的资源冲突导致进程陷入等待。

2. Ubuntu与Windows的核心差异

  • 进程启动方式:Ubuntu默认用fork创建子进程,会复制父进程的内存空间,包括未清理的CUDA上下文、OpenMP线程池状态,容易引发资源冲突;Windows只能用spawn,会重新初始化Python解释器和CUDA环境,资源隔离更彻底。
  • 调度器与IO模型:Linux的CFS调度器在多进程密集场景下,若进程频繁切换或出现IO阻塞,调度延迟会显著增加;Windows的IOCP模型对磁盘异步IO的处理更高效,减少进程因等待IO而被挂起的概率。
  • CUDA/OpenMP的资源管理:Linux下CUDA上下文默认绑定到进程,fork后的子进程可能共享未正确初始化的CUDA资源,导致内核态等待;Windows下每个进程的CUDA上下文独立,冲突概率更低。

3. 具体解决步骤

  • 强制使用spawn启动方式:在__main__开头添加:
    if __name__ == '__main__':
        multiprocessing.set_start_method('spawn')
        # 后续代码不变
    
    spawn会增加进程启动开销,但能彻底隔离CUDA/OpenMP资源,避免fork带来的上下文污染。
  • 严格控制进程数与GPU绑定:
    • 进程数不要超过GPU数量×单GPU可承载并行任务数,建议设置为4×8=32(L4单卡可支持8个左右并行CUDA任务),远低于96或40,减少CPU调度竞争。
    • 确保每个进程绑定固定GPU,避免跨GPU调度开销,可在run_sim开头添加CUDA设备设置:
      import torch  # 或直接调用CUDA API
      torch.cuda.set_device(gpu_device_list[0])  # 假设每个任务绑定单个GPU
      
  • 优化磁盘IO:
    • 将子任务的磁盘写入改为批量操作,减少随机IO;使用os.sync()或异步IO库(如aiofiles)避免进程因等待磁盘刷新而阻塞。
    • 检查AWS实例的磁盘类型,确保使用IO2/io3高性能SSD,避免磁盘带宽成为瓶颈。
  • 监控进程状态与资源:
    • 用htop观察进程的CPU/GPU占用、IO等待时间;用nvidia-smi dmon监控GPU的利用率、内存和带宽。
    • 用strace -p <pid>跟踪阻塞进程的系统调用,定位具体的等待点(如锁、IO、CUDA内核调用)。
  • 调整OpenMP线程数:
    • 在环境变量中限制每个进程的OpenMP线程数,避免多进程的OpenMP线程抢占CPU:
      import os
      os.environ['OMP_NUM_THREADS'] = '2'  # 每个进程用2个OpenMP线程,总线程数=32×2=64 < 96vCPU
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 19:07:22