只是想知道什么是决定何时停止在作为线程多次运行相同程序的单核机器上停止创建新线程的最佳方法?
线程正在获取 Web 内容并进行一些处理,这意味着每个线程的负载在线程终止之前一直不是恒定的。
我正在考虑有一个线程来监视 CPU/RAM 负载,如果负载达到某个阈值,则停止创建线程,但如果达到某个线程数,也停止创建线程,以确保 CPU 不会超载。
关于有哪些技术可以实现这一目标的任何反馈?
非常感谢,弗拉基米尔
只是想知道什么是决定何时停止在作为线程多次运行相同程序的单核机器上停止创建新线程的最佳方法?
线程正在获取 Web 内容并进行一些处理,这意味着每个线程的负载在线程终止之前一直不是恒定的。
我正在考虑有一个线程来监视 CPU/RAM 负载,如果负载达到某个阈值,则停止创建线程,但如果达到某个线程数,也停止创建线程,以确保 CPU 不会超载。
关于有哪些技术可以实现这一目标的任何反馈?
非常感谢,弗拉基米尔
通过监视当前进程使用的 CPU 将很难做到这一点。这些数字往往落后于现实,结果将在很大程度上成为高峰和低谷。问题是您的线程大多会被 IO 阻塞,并且没有任何好的方法可以预测在不久的将来何时可以读取字节。
也就是说,您可以从ThreadPoolExecutor
某个最大线程数开始(对于单个处理器,比如说 4),然后每 10 秒左右检查一次负载平均值。如果负载平均值低于您想要的值,那么您可以setMaximumPoolSize(...)
使用更大的值调用以在接下来的 10 秒内增加它。您可能需要在每次计算之间轮询 30 秒或更长时间以平滑应用程序的性能。
您可以使用以下代码来跟踪所有线程的总 CPU 时间。不确定这是否是最好的方法
long total = 0;
for (long id : threadMxBean.getAllThreadIds()) {
long cpuTime = threadMxBean.getThreadCpuTime(id);
if (cpuTime > 0) {
total += cpuTime;
}
}
// since is in nano-seconds
long currentCpuMillis = total / 1000000;
您可以考虑尝试最大化吞吐量,而不是尝试最大化蜘蛛的 CPU 级别。以每单位时间爬取的页面数为样本,并增加或减少您的最大线程数,ExecutorService
直到最大化。
要考虑的一件事是使用 NIO 和选择器,这样你的线程总是很忙,而不是总是等待 IO。这是关于 NIO/Selectors 的一个很好的示例教程。你也可以考虑使用Pyronet,它似乎在 NIO 周围提供了一些很好的特性。
如果异步 I/O 不适合,我会考虑使用线程池,例如ThreadPoolExecutor,这样您就没有创建、销毁和重新创建线程的开销。
然后我会进行性能测试以调整最大线程数以提供最佳性能。
您可以从 10 个线程开始,然后使用 20 个线程重新运行性能测试,直到找到最佳值。同时我会使用系统工具(取决于你的操作系统)来监控线程运行队列、JVM等。
对于性能测试,您必须确保您的测试是可重复的(即使用相同的输入)并代表您的程序将使用的实际输入。