前言
线程属性包括是否分离、亲和性、调度策略和优先级等。Linux默认的调度策略是CFS(完全公平调度算法),而 Windows 是基于优先级抢占式的策略。
在这些方面,Windows 和 Linux 差异巨大。本文仅针对 Windows 系统的线程亲和性进行探讨。
线程亲和性(Thread affinity)
什么是线程亲和性(Thread affinity)?
线程亲和性(Thread affinity)指进程和 CPU 核的亲和性,即线程在某个给定的 CPU 上尽量长时间地运行而不被迁移到其他处理器的倾向性。
通俗的说就是将线程绑定到 CPU 上某一个或多个核上。注意,此处的核是指逻辑核心,而非物理核心。
称为线程绑定CPU,更好理解一些。
为什么要设置线程亲和性(Thread affinity)?
简单说,为了提升执行效率。
首先,这个问题是随着CPU多核多线程技术而来的。
对于应用程序来说,感知到的是逻辑CPU,物理 CPU(主板上插着的CPU)包含多个核心,如常说8核CPU,就对应了8个逻辑CPU。超线程技术(Hyper-Threading)进一步,利用特殊的硬件指令将两个逻辑CPU模拟成两个两个物理CPU,实现了多核多线程。
最终,逻辑CPU数量 = 物理CPU数量 x CPU cores x 2(如果支持并开启HT)
在多核系统上,操作系统通常可以在不同内核之间自由移动进程和线程,以确保整体工作负载均匀分布在可用内核上。这在通用计算机(如同时运行大量应用程序的笔记本电脑)上非常有用。
但是,移动进程和线程可能会导致性能问题。
每个 CPU 有独立的缓存,即CPU cache(高速缓冲存储器)。缓存着进程、线程的数据。在不绑定 CPU 的情况下,线程会被系统调度到其他 CPU 上,CPU cache 命中率很低,需要从内存、硬盘加载对应的数据,代价非常昂贵。而绑定 CPU 后,线程始终(或大概率)跑在指定的CPU上,性能会有进一步的提升。
通过绑定CPU,减少上下文切换、缓存未命中和内存访问延迟提高了程序的执行效率。
什么时候需要设置线程亲和性(Thread affinity)?
那么,是不是任何时候将线程绑定到特定 CPU 就能达到最佳执行效率呢?
不!
设置线程亲和性通常是为了优化特定类型的应用程序的性能,特别是在那些对性能要求极高的场景中。例如高性能计算(High-Performance Computing, HPC)、实时系统(Real-time Systems)、数据库、多级缓存优化、特定硬件操作等。
对于大多数常规的应用程序,操作系统的调度器已经足够智能,能够根据当前的系统负载和资源使用情况做出合理的调度决策。强制设置线程亲和性可能不会带来显著的性能提升,甚至可能引起一些问题,如资源利用率不均、系统响应性下降、兼容性问题、热管理问题甚至性能下降。
在大多数情况下,让操作系统的调度器来管理线程调度是更好的选择。
如何设置线程亲和性
在 Windows 上,通过任务管理器即可手动调整。