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繁忙直到程序结束,亲和性修改未生效。
原因分析
问题核心在于进程亲和性与线程亲和性的继承逻辑:
os.sched_setaffinity(pid, ...)修改的是进程级的亲和性掩码,这个掩码仅作为进程后续新建线程的默认亲和性,不会自动覆盖已存在线程的亲和性设置。- 你的C++程序启动后立刻创建了所有工作线程,这些线程继承了进程初始(或前10秒设置的
a集合)的亲和性。10秒后修改进程亲和性时,已在运行的线程不会主动更新自己的核心绑定,因此会继续在原核心执行。 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
相关产品推荐
相关产品推荐

