如何将t个线程分配到指定CPU?ThreadPool相关技术疑问
核心认知澄清
你用multiprocessing.ThreadPool创建的是同一进程下的多个线程,而os.sched_setaffinity()是针对进程设置CPU亲和掩码的工具——线程作为进程的执行单元,会共享进程的CPU亲和性配置,也就是说:给线程所在的进程设置亲和性,该进程内的所有线程都会被限制在指定的CPU核心上运行。
所以你要把t个线程平均分配到p个CPU的需求,本质上是要控制进程的CPU亲和范围,或者如果需要更精细的单线程绑定,得用更底层的方法(但Python标准库不直接支持)。
你的疑问解答
是否需要线程的进程ID来为其分配指定CPU?
不需要。线程没有独立的PID,它和所属进程共用同一个PID。os.sched_setaffinity()接收的是进程ID,设置后该进程下的所有线程都会遵循这个亲和规则。如果要给单个线程绑定特定CPU,Python标准库没有原生接口,需要通过ctypes调用系统底层的pthread_setaffinity_np(仅Linux等类UNIX系统可用),但这种操作对于ThreadPool的池化线程来说意义不大,因为线程会被复用。能否在线程运行前获取其进程ID?
线程没有独立的PID,它的PID就是所属进程的PID。你可以在创建ThreadPool前,用os.getpid()获取当前进程的PID,这个PID就是所有池内线程的PID。
代码调整建议
如果你的任务是CPU密集型(比如计算皮尔逊相关系数),更建议用multiprocessing.Pool(多进程池)而非线程池,因为Python的GIL会限制多线程的CPU并行效率。用多进程的话,可以给每个子进程单独设置CPU亲和性,实现更均匀的分配:
import os import multiprocessing def pearson_cor(j, split_x_j, y, n, len_split): # 子进程内设置亲和性:把第j个进程绑定到j%p号CPU p = 4 # 替换成你的CPU核心数 os.sched_setaffinity(0, {j % p}) # 0表示当前进程 # 你的计算逻辑 ... if __name__ == "__main__": t = 8 # 替换成你的进程数 p = 4 # 替换成你的CPU核心数 pool = multiprocessing.Pool(processes=t) threads = [] for j in range(t): threads.append(pool.apply_async(pearson_cor, args=(j, split_x[j], y, n, len(split_x[j])))) correct_rs = [] for thread in threads: correct_rs.extend(thread.get()) pool.close() pool.join()
如果坚持用线程池,只需在创建ThreadPool前给主进程设置亲和性,让所有线程都在指定CPU范围内运行:
import os from multiprocessing.pool import ThreadPool def pearson_cor(j, split_x_j, y, n, len_split): # 你的计算逻辑 ... if __name__ == "__main__": t = 8 p = 4 # 设置主进程的CPU亲和性:允许在0到p-1号CPU上运行 os.sched_setaffinity(0, set(range(p))) pool = ThreadPool(processes=t) threads = [] for j in range(t): threads.append(pool.apply_async(pearson_cor, args=(j, split_x[j], y, n, len(split_x[j])))) correct_rs = [] for thread in threads: correct_rs.extend(thread.get()) pool.close() pool.join()
内容的提问来源于stack exchange,提问作者Gie Grajo

