【问题标题】:Optimising max number of threads running on a CPU优化 CPU 上运行的最大线程数
【发布时间】:2013-02-25 17:43:38
【问题描述】:

只是想知道什么是决定何时停止在单核机器上停止创建新线程的最佳方法,该机器作为一个线程多次运行相同的程序?

线程正在获取网页内容并进行一些处理,这意味着每个线程的负载在线程终止之前并不是一直不变的。

我正在考虑有一个线程来监视 CPU/RAM 负载,如果负载达到某个阈值,则停止创建线程,但如果达到某个线程数,也停止创建线程,以确保 CPU不会超载。

您对目前有哪些技术可以实现这一目标有任何反馈吗?

非常感谢, 弗拉基米尔

【问题讨论】:

  • 我认为你是在正确的轨道上。要考虑的一件事是使用 NIO 和选择器,这样你的线程总是很忙,而不是总是等待 IO。如果没有高峰和低谷,就很难最大限度地提高吞吐量。
  • 在那里,Gray 击败了我 :) 使用阻塞 IO,您将需要大量可笑的线程,这将浪费 RAM,而且除了等待之外几乎什么都不做。
  • 您可能不想自己创建线程。使用ExecutorService,它为RunnableCallable任务重用线程并减少创建销毁线程的开销。

标签: java multithreading


【解决方案1】:

很难通过监视当前进程使用的 CPU 来做到这一点。这些数字往往落后于现实,结果将在很大程度上成为高峰和低谷。问题是您的线程大多会被 IO 阻塞,并且没有任何好的方法可以预测在不久的将来何时可以读取字节。

也就是说,您可以在某个最大线程数(对于单个处理器,比如说 4)开始使用 ThreadPoolExecutor,然后每 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。这是good example tutorial about NIO/Selectors。您也可以考虑使用Pyronet,它似乎为 NIO 提供了一些不错的功能。

【讨论】:

  • 我想知道。我点击了Pyronet,它有大约 150 次下载。为什么有人会在项目中包含一个用户群如此之少的库?
  • 在没有替代方案之前,您不想重新发明轮子@Cratylus。 :-)
【解决方案2】:

如果异步 I/O 不合适,我会考虑使用线程池,例如ThreadPoolExecutor,因此您没有创建、销毁和重新创建线程的开销。

然后我会进行性能测试以调整最大线程数以提供最佳性能。

您可以从 10 个线程开始,然后使用 20 个线程重新运行性能测试,直到找到最佳值。同时我会使用系统工具(取决于你的操作系统)来监控线程运行队列、JVM等。

对于性能测试,您必须确保您的测试是可重复的(即使用相同的输入)并代表您的程序将使用的实际输入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 2013-11-03
    相关资源
    最近更新 更多