为什么我的 java 长 运行 线程(5k+ 线程)没有利用所有机器内核(12 个内核)?
Why my java long running Threads (5k+ thread) not utilizing all machines cores (12 cores)?
我写了一个简单的多线程 java 应用程序,main 方法只创建了 5k 个线程,每个线程将遍历一个包含 5M 条记录的列表来处理。
我的机器规格:
- CPU 核心数:12 个核心
- 内存:13Gb RAM
- OS:Debian 64 位
我的 jar 现在是 运行,我使用 hTop 监控我的应用程序,这是我在 运行
时可以看到的
这就是我构建线程的方式:
ExecutorService executor = Executors.newCachedThreadPool();
Future<MatchResult> future = executor.submit(() -> {
Match match = new Match();
return match.find(this);
});
Match.class
find(Main main){
// looping over a list of 5M
// process this values and doing some calculations
// send the result back to the caller
// this function has no problem and it just takes a long time to run (~160 min)
}
现在我有一些问题:
1- 根据我的理解,如果我有一个多线程进程,它将充分利用我所有的内核直到任务完成,那么为什么工作负载只有 0.5 左右(只使用了一半的内核)?
2- 为什么我的 Java 应用程序状态是 "S"(休眠)而实际上是 运行 并填满了日志文件?
3- 为什么我只能看到 5k 中的 2037 个线程是 运行(这个数字实际上小于这个数字并且随着时间的推移它会增加)
我的目标:利用所有核心并尽可能快地完成所有这 5k+ :)
Based on my understanding if I have a multiThreaded process, it'll fully utilize all my cores until the task is completed.
您的理解不正确。在设计不佳的多线程应用程序中可能无法(全部)使用内核的原因有很多。
so why the work load is only around 0.5 (only half a core is used)?
一些可能的原因:
- 线程可能死锁了。
- 线程可能都在争用一个锁(或少量锁),导致大多数线程都在等待。
- 线程可能都在等待 I/O;例如从一些数据库中读取记录。
这些只是一些更明显的可能原因。
鉴于您的线程正在取得 一些 进展,我认为解释 #2 非常适合您的 "symptoms"。
就其价值而言,创建 5k 个线程几乎肯定是一个非常糟糕的主意。最多 12 个可能随时 运行ning。其余的将等待 运行(假设您解决了导致线程饥饿的问题)并占用内存。后者具有各种次要性能效果。
My Target: to utilize all cores and get all this 5k+ done as fast as it can be :)
这两个目标可能互斥 :-)
All threads are logging to the same file by a the java.util.Logger.
这可能导致他们都争用同一个锁……在记录器框架中的某个东西上。或日志文件的文件 I/O 出现瓶颈。
一般来说,日志记录是昂贵的。如果您想要性能,请尽量减少日志记录,并且在日志记录必不可少的情况下,请使用不会引入并发瓶颈的日志记录框架。
解决此问题的最佳方法是剖析 代码并找出它花费大部分时间的地方。
猜测是低效的。
谢谢你们,我已经解决了这个问题,现在我有 12 个内核 运行 最大,如图所示。 :)
我实际上尝试 运行 这个命令 jstack <Pid>
来查看我所有 运行ning 线程在这个进程 ID 中的状态,我发现我的线程有 95% 是实际上在 logging
行被阻塞,我进行了一些谷歌搜索,发现我可以在 log4J 中使用 AsynchAppender,因此日志记录不会阻塞线程
我写了一个简单的多线程 java 应用程序,main 方法只创建了 5k 个线程,每个线程将遍历一个包含 5M 条记录的列表来处理。
我的机器规格:
- CPU 核心数:12 个核心
- 内存:13Gb RAM
- OS:Debian 64 位
我的 jar 现在是 运行,我使用 hTop 监控我的应用程序,这是我在 运行
时可以看到的这就是我构建线程的方式:
ExecutorService executor = Executors.newCachedThreadPool();
Future<MatchResult> future = executor.submit(() -> {
Match match = new Match();
return match.find(this);
});
Match.class
find(Main main){
// looping over a list of 5M
// process this values and doing some calculations
// send the result back to the caller
// this function has no problem and it just takes a long time to run (~160 min)
}
现在我有一些问题:
1- 根据我的理解,如果我有一个多线程进程,它将充分利用我所有的内核直到任务完成,那么为什么工作负载只有 0.5 左右(只使用了一半的内核)?
2- 为什么我的 Java 应用程序状态是 "S"(休眠)而实际上是 运行 并填满了日志文件?
3- 为什么我只能看到 5k 中的 2037 个线程是 运行(这个数字实际上小于这个数字并且随着时间的推移它会增加)
我的目标:利用所有核心并尽可能快地完成所有这 5k+ :)
Based on my understanding if I have a multiThreaded process, it'll fully utilize all my cores until the task is completed.
您的理解不正确。在设计不佳的多线程应用程序中可能无法(全部)使用内核的原因有很多。
so why the work load is only around 0.5 (only half a core is used)?
一些可能的原因:
- 线程可能死锁了。
- 线程可能都在争用一个锁(或少量锁),导致大多数线程都在等待。
- 线程可能都在等待 I/O;例如从一些数据库中读取记录。
这些只是一些更明显的可能原因。
鉴于您的线程正在取得 一些 进展,我认为解释 #2 非常适合您的 "symptoms"。
就其价值而言,创建 5k 个线程几乎肯定是一个非常糟糕的主意。最多 12 个可能随时 运行ning。其余的将等待 运行(假设您解决了导致线程饥饿的问题)并占用内存。后者具有各种次要性能效果。
My Target: to utilize all cores and get all this 5k+ done as fast as it can be :)
这两个目标可能互斥 :-)
All threads are logging to the same file by a the java.util.Logger.
这可能导致他们都争用同一个锁……在记录器框架中的某个东西上。或日志文件的文件 I/O 出现瓶颈。
一般来说,日志记录是昂贵的。如果您想要性能,请尽量减少日志记录,并且在日志记录必不可少的情况下,请使用不会引入并发瓶颈的日志记录框架。
解决此问题的最佳方法是剖析 代码并找出它花费大部分时间的地方。
猜测是低效的。
谢谢你们,我已经解决了这个问题,现在我有 12 个内核 运行 最大,如图所示。 :)
我实际上尝试 运行 这个命令 jstack <Pid>
来查看我所有 运行ning 线程在这个进程 ID 中的状态,我发现我的线程有 95% 是实际上在 logging
行被阻塞,我进行了一些谷歌搜索,发现我可以在 log4J 中使用 AsynchAppender,因此日志记录不会阻塞线程