当忙于旋转的 Java 线程绑定到物理内核时,是否可以由于到达代码中的新分支而发生上下文切换?
我对低延迟代码感兴趣,这就是我尝试配置线程相关性的原因。特别是,它应该有助于避免上下文切换。
我已使用 https://github.com/OpenHFT/Java-Thread-Affinity 配置了线程关联。我运行非常简单的测试代码,只是在一个周期中旋转检查时间条件。
long now = start;
while (true)
{
if (now < start + TimeUtils.NANOS_IN_SECOND * delay)
{
now = TimeUtils.now();
}
else
{
// Will be printed after 30 sec
if (TimeUtils.now() > start + TimeUtils.NANOS_IN_SECOND * (delay + 30))
{
final long finalNow = now;
System.out.println("Time is over at " +
TimeUtils.toInstant(finalNow) + " now: " +
TimeUtils.toInstant(TimeUtils.now()));
System.exit(0);
}
}
}
因此,在指定的延迟执行转到“else”之后,大约同时我看到上下文切换。这是预期的行为吗?具体原因是什么?在这种情况下,如何避免上下文切换?
测试详细信息
我从这个存储库构建shadowJar:https://github.com/stepan2271/thread-affinity-example。然后我使用以下命令运行它(可以在这里玩数字,当延迟>60时,它对测试没有显着影响):
taskset -c 19 java -DtestLoopBindingCpu=3 -Ddelay=74 -cp demo-all.jar main.TestLoop
我还有以下测试脚本来监视上下文切换(应使用绑定到核心的 Java 线程的 ID 运行)
#!/bin/bash
while [ true ]
do
date >> ~/demo-ctxt-switches.log
cat /proc/$1/status | grep ctxt >> ~/demo-ctxt-switches.log
sleep 3
done
此脚本的典型输出如下:
Fri Oct 16 18:23:29 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:32 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:35 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:38 MSK 2020
voluntary_ctxt_switches: 90
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:41 MSK 2020
voluntary_ctxt_switches: 91
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:44 MSK 2020
voluntary_ctxt_switches: 91
nonvoluntary_ctxt_switches: 37
Fri Oct 16 18:23:47 MSK 2020
voluntary_ctxt_switches: 91
nonvoluntary_ctxt_switches: 37
因此,在开始时间发生一些变化之后,这些数字变得稳定,然后在代码到达“else”分支时,我看到1到3个开关(差异小于1秒)。
偏差
基本配置几乎每次都会重现此行为,而一些偏差会导致我无法重现的情况。例子:
https://github.com/stepan2271/thread-affinity-example/tree/without-log4j
https://github.com/stepan2271/thread-affinity-example/tree/without-cached-nano-clock
测试环境
2 * 英特尔(R) 至强(R) 金牌 6244 CPU @ 3.60GHz
Red Hat Enterprise Linux 8.1 (Ootpa)
内核使用 /etc/systemd/system.conf 和 /etc/systemd/user.conf 中的 CPUAffinity 进行隔离
/etc/sysconfig/irqbalance is configuration.
Openjdk 11.0.6 2020-01-14 LTS 运行时环境 18.9