Thread Affinity
为什么需要线程的CPU亲和性
应用通过多线程的方式执行,多数情况下线程能够被合理的调度。但在某些情况下某个重要的线程被暂停,而时间片被分配给了一个无关重要的线程。当一个线程每次被暂停休眠,然后被唤醒之后,需要重新加载“cache line”(cpu L1/L2 cache)。当线程的工作时间很短暂,需要被频繁的被唤醒,意味着整个流程执行都很慢,有可能比单线程情况下慢2-5倍。
应用的有些线程可能需要一直执行,不因CPU的调度而休眠,这需要使线程一直在某个CPU上执行。
https://github.com/OpenHFT/Java-Thread-Affinity实现了将线程绑定到CPU上,例如:线程X必须使用一个物理CPU,线程Y和Z使用同一个物理CPU的不同逻辑CPU(CPU超线程技术)。这个代码能够识别独立的CPU,根据开发人员提供的规则将线程绑定到合适的CPU上。这个工具能够识别独立的CPU,基于最优效果原则,根据提供的规则将线程分配到CPU上。即使没有独立的核心也能做到最好。
原理
这个工具读取/proc/cpuinfo/来决定CPU的布局。如果没有这个文件则认为每个CPU一个插槽。
默认情况只在未被使用的CPU上来查询独立的CPU。例如总共16个CPU,有8个在通常不被使用(在启动时候设定的线程亲和性决定的),那么Java-Thread-Affinity会使用这些CPU。
注意
如果多个进程程使用这个库,则需要为某个进程指定CPU,否则这几个进程会共用CPU。在命令行添加-Daffinity.reserved={cpu-mark-in-hex} 就可以指定进程使用哪个CPU来解决问题。
PS
这篇文章中提到上下文切换的时间损耗:http://ifeve.com/java-context-switch/
线程切换的原因
- 1、当前执行任务的时间片用完之后,系统CPU正常调度下一个任务。
- 2、 当前执行任务碰到IO阻塞, 调度器将挂起此任务, 继续下一任务
- 3、 多个任务抢占锁资源, 当前任务没有抢到,被调度器挂起, 继续下一任务
- 4、 用户代码挂起当前任务, 让出CPU时间
- 5、 中断。硬件中断:外设发送电信号给处理器,异步,IRQ(interrupt request);软中断:异常情况 or 特殊指令集,软中断可以用来实现system call。
上下文切换涉及:saving and loading registers and memory maps, updating various tables and lists etc.
A context switch can mean aregister context switch, atask context switch, astack frame switch, athread context switch, or a process context switch.(表现形式:进程之间,线程之间,栈帧之间)