调度器的参数
参数简介:
-
sched_min_granularity_ns:CFS 设定了进程占用 CPU 的最小时间值,sched_min_granularity_ns,正在 CPU 上运行的进程如果不足这个时间是不可以被调离 CPU 的。 -
sched_latency_ns:设定一个调度周期(sched_latency_ns),目标是让每个进程在这个周期内至少有机会运行一次,换一种说法就是每个进程等待 CPU 的时间最长不超过这个调度周期;然后根据进程的数量,大家平分这个调度周期内的 CPU 使用权,由于进程的优先级即nice值不同,分割调度周期的时候要加权。
如果进程数量太多的话,就会造成 CPU 时间片太小,如果小于
sched_min_granularity_ns的话就以sched_min_granularity_ns为准;而调度周期也随之不再遵守sched_latency_ns,而是以(sched_min_granularity_ns* 进程数量)的乘积为准。
实际配置:
$ uname -a
Linux dev.xxx.net 4.19.0-17-amd64 #1 SMP Debian 4.19.194-1 (2021-06-10) x86_64 GNU/Linux
$ cat /proc/sys/kernel/sched_min_granularity_ns
3000000
$ cat /proc/sys/kernel/sched_latency_ns
24000000
单位转换:
测试代码
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TestThread {
private static int threadCount = 10;
private static int calcCount = 10000;
public static void main(String[] args) throws InterruptedException {
if (args.length >= 1) {
threadCount = Integer.parseInt(args[0]);
}
if (args.length >= 2) {
calcCount = Integer.parseInt(args[1]);
}
System.out.println(LocalDateTime.now());
System.out.println(Runtime.getRuntime().availableProcessors());
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(threadCount);
for (int i = 0; i < threadCount; ++i) {
String task = "task_" + i;
System.out.println(LocalDateTime.now() + " -- [" + task + "] 分配线程");
executorService.scheduleAtFixedRate(() -> spin(task, calcCount), 0, 500, TimeUnit.MILLISECONDS);
}
}
public static void spin(String task, int count) {
System.out.println(LocalDateTime.now() + " -- [" + task + "] spin 开始, 当前线程:" + Thread.currentThread().getName());
long startTime = System.currentTimeMillis();
long tempStartTime = startTime;
long num = 1;
long max = 0;
max = Math.max(System.currentTimeMillis() - tempStartTime, max);
for (int i = 0; i < count; ++ i) {
num = num * 3;
max = Math.max(System.currentTimeMillis() - tempStartTime, max);
tempStartTime = System.currentTimeMillis();
}
long stopTime = System.currentTimeMillis();
System.out.println(LocalDateTime.now() + " -- [" + task + "] spend time = " + (stopTime - startTime) + "(ms) num = "
+ num + " 当前线程:" + Thread.currentThread().getName() + "max = " + max);
}
}
jmx 参数:
-Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
线程数量:1
$ java TestThread 1 50000
2021-07-20T21:22:04.818
1
2021-07-20T21:22:04.825 -- [task_0] 分配线程
2021-07-20T21:22:04.847 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:04.866 -- [task_0] spend time = 19(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:05.343 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:05.357 -- [task_0] spend time = 13(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:05.843 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:05.851 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:06.343 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:06.351 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:06.843 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:06.851 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:07.343 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:07.350 -- [task_0] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:07.842 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:07.850 -- [task_0] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:08.343 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:08.351 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:08.843 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:08.850 -- [task_0] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:22:09.343 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:22:09.351 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
通过 1 个线程的测试,可以发现执行 50000 次循环大概要 8ms。
线程数量:3
$ java TestThread 3 50000
2021-07-20T21:27:14.824
1
2021-07-20T21:27:14.831 -- [task_0] 分配线程
2021-07-20T21:27:14.849 -- [task_1] 分配线程
2021-07-20T21:27:14.850 -- [task_2] 分配线程
2021-07-20T21:27:14.850 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:27:14.851 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:27:14.854 -- [task_2] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:27:14.883 -- [task_0] spend time = 32(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:27:14.883 -- [task_1] spend time = 32(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:27:14.886 -- [task_2] spend time = 32(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:27:15.350 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:27:15.350 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:27:15.350 -- [task_2] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:27:15.403 -- [task_2] spend time = 53(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:27:15.404 -- [task_0] spend time = 54(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:27:15.405 -- [task_1] spend time = 55(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:27:15.849 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:27:15.850 -- [task_1] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:27:15.850 -- [task_2] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:27:15.857 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:27:15.860 -- [task_2] spend time = 10(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:27:15.860 -- [task_1] spend time = 10(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:27:16.349 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:27:16.350 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:27:16.350 -- [task_2] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:27:16.357 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:27:16.358 -- [task_1] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:27:16.358 -- [task_2] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:27:16.849 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:27:16.850 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:27:16.850 -- [task_2] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:27:16.856 -- [task_0] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:27:16.858 -- [task_1] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:27:16.858 -- [task_2] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:27:17.349 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:27:17.350 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:27:17.350 -- [task_2] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:27:17.356 -- [task_0] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:27:17.357 -- [task_1] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:27:17.358 -- [task_2] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
3 个线程,一个线程执行 8ms,符合 sched_latency_ns = 24ms 的值,说明在 sched_latency_ns 范围内每个线程都会执行一次,即不会被切换上下文。
后面输出的日志也说明了这一点。
线程数量:4
$ java TestThread 4 50000
2021-07-20T21:30:23.714
1
2021-07-20T21:30:23.721 -- [task_0] 分配线程
2021-07-20T21:30:23.740 -- [task_1] 分配线程
2021-07-20T21:30:23.741 -- [task_2] 分配线程
2021-07-20T21:30:23.742 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:23.743 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:23.744 -- [task_3] 分配线程
2021-07-20T21:30:23.747 -- [task_2] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:23.750 -- [task_3] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:23.778 -- [task_0] spend time = 36(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:23.779 -- [task_3] spend time = 29(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 1
2021-07-20T21:30:23.781 -- [task_1] spend time = 38(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:23.781 -- [task_2] spend time = 34(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:30:24.241 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:24.241 -- [task_1] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:24.242 -- [task_2] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:24.245 -- [task_3] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:24.288 -- [task_1] spend time = 47(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 1
2021-07-20T21:30:24.299 -- [task_0] spend time = 58(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:24.299 -- [task_2] spend time = 57(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:24.300 -- [task_3] spend time = 55(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:30:24.740 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:24.741 -- [task_1] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:24.742 -- [task_2] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:24.745 -- [task_3] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:24.749 -- [task_0] spend time = 9(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:24.752 -- [task_1] spend time = 11(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 1
2021-07-20T21:30:24.754 -- [task_2] spend time = 12(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:24.755 -- [task_3] spend time = 10(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:30:25.240 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:25.241 -- [task_1] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:25.241 -- [task_2] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:25.245 -- [task_3] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:25.248 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:25.249 -- [task_1] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 1
2021-07-20T21:30:25.254 -- [task_2] spend time = 12(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:25.257 -- [task_3] spend time = 12(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 5
2021-07-20T21:30:25.740 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:25.741 -- [task_1] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:25.742 -- [task_2] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:25.745 -- [task_3] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:25.748 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:25.750 -- [task_2] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:25.750 -- [task_1] spend time = 9(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 1
2021-07-20T21:30:25.753 -- [task_3] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:30:26.240 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:26.241 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:26.242 -- [task_2] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:26.245 -- [task_3] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:26.248 -- [task_0] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:26.249 -- [task_1] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:26.255 -- [task_2] spend time = 13(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 5
2021-07-20T21:30:26.258 -- [task_3] spend time = 12(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:30:26.740 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:26.741 -- [task_1] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:26.742 -- [task_2] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:26.745 -- [task_3] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:26.749 -- [task_1] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:26.749 -- [task_2] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 1
2021-07-20T21:30:26.752 -- [task_3] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:30:26.754 -- [task_0] spend time = 13(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:27.240 -- [task_0] spin 开始, 当前线程:pool-1-thread-1
2021-07-20T21:30:27.241 -- [task_1] spin 开始, 当前线程:pool-1-thread-4
2021-07-20T21:30:27.242 -- [task_2] spin 开始, 当前线程:pool-1-thread-3
2021-07-20T21:30:27.245 -- [task_3] spin 开始, 当前线程:pool-1-thread-2
2021-07-20T21:30:27.248 -- [task_0] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-1max = 1
2021-07-20T21:30:27.249 -- [task_2] spend time = 7(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 1
2021-07-20T21:30:27.253 -- [task_3] spend time = 8(ms) num = -246746203963084735 当前线程:pool-1-thread-2max = 1
2021-07-20T21:30:27.257 -- [task_1] spend time = 16(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 8
4 个线程,一个线程执行 8ms,大于 sched_latency_ns = 24ms 的值,说明在 sched_latency_ns 范围内每个线程无法执行都一次,因此会被切换上下文。
日志中的 max=5 和 max=8 说明发生了线程切换。
...
2021-07-20T21:30:25.257 -- [task_3] spend time = 12(ms) num = -246746203963084735 当前线程:pool-1-thread-3max = 5
...
2021-07-20T21:30:26.255 -- [task_2] spend time = 13(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 5
...
2021-07-20T21:30:27.257 -- [task_1] spend time = 16(ms) num = -246746203963084735 当前线程:pool-1-thread-4max = 8
...
系统负载
$ uptime
10:31:23 up 262 days, 13:01, 2 users, load average: 0.02, 0.05, 0.21
$ java TestThread 500
$ uptime
10:34:04 up 262 days, 13:04, 2 users, load average: 0.84, 0.31, 0.27









网友评论