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

Linux下用Python实时修改CPU亲和性失效问题排查

问题:os.sched_setaffinity修改进程CPU亲和性后未实时生效

我尝试用os.sched_setaffinity设置进程的CPU亲和性,但发现无法实时调整已运行线程的核心绑定。具体场景与代码如下:

C++ 计算程序(test.cpp)

// test.cpp
#include <iostream>
#include <thread>
#include <vector>

void workload() {
    unsigned long long int sum = 0;
    for (long long int i = 0; i < 50000000000; ++i) {
        sum += i;
    }
    std::cout << "Sum: " << sum << std::endl;
}

int main() {
    unsigned int num_threads = std::thread::hardware_concurrency();
    std::cout << "Creating " << num_threads << " threads." << std::endl;

    std::vector<std::thread> threads;
    for (unsigned int i = 0; i < num_threads; ++i) {
        threads.push_back(std::thread(workload));
    }

    for (auto& thread : threads) {
        thread.join();
    }

    return 0;
}

编译命令:

g++ test.cpp -O0

Python 控制程序(test.py)

# test.py
from subprocess import Popen
import os
import time
a = set(range(8, 16))
b = set(range(4, 12))

if __name__ == "__main__":
    proc = Popen("./a.out", shell=True)
    pid = proc.pid
    print("pid", pid)
    tic = time.time()
    while True:
        if time.time() - tic < 10:
            os.sched_setaffinity(pid, a)
            print("a", os.sched_getaffinity(pid))
        else:
            os.sched_setaffinity(pid, b)
            print("b", os.sched_getaffinity(pid))
        res = proc.poll()
        if res is None:
            time.sleep(1)
        else:
            break

现象

a.out运行时间较长,预期前10秒CPU 815繁忙、07空闲;10秒后CPU 4~11繁忙、其他核心空闲。但实际通过htop观察:前10秒符合预期,10秒后虽然打印显示进程亲和性已设置为b {4,5,6,7,8,9,10,11},但htop仍显示CPU 8~15繁忙直到程序结束,亲和性修改未生效。


原因分析

问题核心在于进程亲和性与线程亲和性的继承逻辑:

  1. os.sched_setaffinity(pid, ...)修改的是进程级的亲和性掩码,这个掩码仅作为进程后续新建线程的默认亲和性,不会自动覆盖已存在线程的亲和性设置。
  2. 你的C++程序启动后立刻创建了所有工作线程,这些线程继承了进程初始(或前10秒设置的a集合)的亲和性。10秒后修改进程亲和性时,已在运行的线程不会主动更新自己的核心绑定,因此会继续在原核心执行。
  3. os.sched_getaffinity(pid)返回的是进程的亲和性掩码,而非线程的,所以打印结果看起来修改成功,但实际线程的亲和性并未改变。

解决方案

要实时调整所有线程的亲和性,需要遍历进程下的所有线程,逐个修改它们的亲和性:

修改后的Python代码:

# test.py
from subprocess import Popen
import os
import time

a = set(range(8, 16))
b = set(range(4, 12))

def set_all_thread_affinity(pid, mask):
    # 遍历进程下的所有线程tid(Linux系统下的/proc文件系统)
    task_dir = f"/proc/{pid}/task/"
    if not os.path.exists(task_dir):
        return
    for tid_str in os.listdir(task_dir):
        try:
            tid = int(tid_str)
            os.sched_setaffinity(tid, mask)
        except (ValueError, PermissionError):
            continue

if __name__ == "__main__":
    proc = Popen("./a.out", shell=True)
    pid = proc.pid
    print("pid", pid)
    tic = time.time()
    while True:
        current_mask = a if time.time() - tic < 10 else b
        # 修改进程亲和性(给后续新建线程用)
        os.sched_setaffinity(pid, current_mask)
        # 修改所有已有线程的亲和性
        set_all_thread_affinity(pid, current_mask)
        print(f"Current mask: {os.sched_getaffinity(pid)}")
        
        res = proc.poll()
        if res is None:
            time.sleep(1)
        else:
            break

验证

修改后运行程序,通过htop观察,10秒后线程会自动迁移到4~11核心,符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:41:11