减少Java程序的CPU使用率

7

你好-

我们工作中有一些热衷于使用的疯子

while(true) { //Code } 

在他们的代码中,不断轮询互联网以获取站点更新信息,这会导致CPU使用率达到最大。有没有人知道如何减少CPU利用率,以便其他人也可以使用该服务器。

代码本身只是在不断轮询互联网以获取站点更新信息。因此,我想一个小的睡眠方法会大大降低CPU使用率。

此外,所有操作都是在字符串对象(Java)中进行的。是否有人知道使用StringBuilder可以减少多少开销?

感谢任何指导。


4
while (true) 是一种习惯用语,表示“一直执行此操作”。它本身不做任何事情;其中的代码才消耗 CPU 周期。如果其中的代码正在进行网络请求,那么在这样做时它将放弃自己的时间片,因此其他用户将获得 theirs;一个 sleep() 不应显着影响整个服务器吞吐量(尽管对于被该程序攻击的服务器来说,这可能会是一个好事)。最后,StringBuilder 可能会改善性能,也可能不会。但这就是为什么存在分析器的原因:它们可以告诉您程序中花费最多时间的内容。 - kdgregory
3
像往常一样,运行一次性能分析器以确定CPU使用情况。然后使用这些数据来批评相应的开发人员。 - Thorbjørn Ravn Andersen
1
针对您的第二个问题,请注意编译器可以使用StringBuilder在字节码中优化字符串连接。有关详细信息,请参阅此帖子:https://dev59.com/JnI_5IYBdhLWcg3wFu_L - Péter Török
9个回答

8
很多关于StringBuilder的“民间智慧”是错误的。例如,将这个改变:
String s = s1 + ":" + s2 + ":" + s3;

转换为:

StringBuilder sb = new StringBuilder(s1);
sb.append(":");
sb.append(s2);
sb.append(":");
sb.append(s3);
String s = sb.toString();
< p > 可能不会使其更快。这是因为Java编译器实际上将连接序列转换为对临时StringBuilder的等效追加序列。除非您在循环中连接字符串,否则最好只使用 + 运算符。这样您的代码将更易读。

另外需要指出的一点是应该使用分析工具来确定代码中可以从性能优化中获益的地方。大多数开发者有关于哪些部分值得优化的直觉并不可靠。


6

我先回答你的第二个问题,我同意其他人的观点,StringBuilder和String的使用取决于特定的字符串操作。我曾经进行过“基准测试”,一般来说,随着新字符串分配的数量增加(通常是连接的形式),总体执行时间会增加。我不会详细介绍,只会说在与String、StringBuffer、String.format()、MessageFormat等比较时,StringBuilder最有效。

我的经验法则是,每当我想要连接超过3个字符串时,我总是使用StringBuilder。

至于你的第一个问题。我们有一个要求将CPU使用率降低到5%。这不是一项容易的任务。我们使用Spring的AOP机制,在CPU密集型方法的任何方法执行之前添加了Thread.sleep()。仅当某些限制已被超出时,才会调用Thread.sleep()。很抱歉,这个限制的计算并不简单。更遗憾的是,我仍然没有获得发布它的许可。所以这只是为了让你进入一个有趣但复杂的轨道,而且这个方法已经被证明可以长期使用。


6
有什么可能的理由需要“不超过5%的CPU时间”?如果你有一个需要大量使用CPU的任务,那么就是这样了。没有其他办法,给代码添加休眠只会使任务变得更耗时。如果你担心某个程序对整个系统资源的影响,那么最明智的做法是简单地降低该程序的优先级。或者购买另一台计算机。 - kdgregory
1
就我个人而言,我非常赞同您的观点!但是,我只是一名普通程序员,并没有“设计”这个解决方案。我的意思是,如果有需要,这种事情是可能做到的 :) - Yaneeve
@Yaneeve..现在问这个有点晚了。你是如何平衡速度和CPU使用率的?我相信,sleep会增加执行时间,从而影响性能。 - bluelurker
1
@bluelurker 这不是很复杂的负载平衡。我们被要求控制最大的CPU使用率而非处理时间。这意味着只要我们没有开始累积积压,就可以了。我们运行了负载测试,并看到考虑到硬件和预期的负载,一切都很好。我认为除了数据的解析和转换外,我们的大部分工作都是磁盘和网络IO有很大帮助。我们试图仅在CPU密集部分插入休眠,而不是IO。由于IO至少比CPU慢一个数量级,因此在中间向IO投放许多线程可能会有所帮助。 - Yaneeve
@Yaneeve.. 这很有趣。 - bluelurker

4

这些网站更新频率有多高?你可能会让主机感到非常烦恼。只需在循环结束处添加Thread.sleep(60 * 1000);,就可以避免这种情况。这将每分钟轮询一次-肯定足够了吧?


2
让它等待一段时间再次触发,就像这样:
while(true) { 
  //Code 
  Thread.sleep (1000); //Wait 1 second
} 

至于第二个问题,这将减少内存使用量,并可能减少CPU使用量,但收益实际上取决于这些字符串的具体使用情况。


2

休眠可以降低CPU使用率。对于StringBuilders,它们可以降低内存使用量并提高性能。


0

你也可以尝试一下

Thread.yield()

4
“Yield”方法只会暂时地让当前执行线程暂停,让其他线程来执行……因此,只有在有其他用户应用程序并行运行时,才会显著降低CPU使用率。如果要实现他想要的效果,“Sleep”方法会更加适合。 - XpiritO
@XpritO 抱歉,你是对的。我没有完全理解 OP 的观点。也许在喝第二杯咖啡之前不应该阅读帖子 ^^. - helpermethod
这就是为什么在CPU负载达到5%时,要给其他应用程序在同一台计算机上留出空间,这可以通过在代码的关键位置放置一些Thread.yield()来实现。我正在这样做,从正常软件使用体验的角度来看,这非常有用。 - ante.sabo

0
如果他们的代码在独立的JVM上运行,并且正在Linux或其他Unix上运行,请要求他们在优先级为20的情况下运行其程序。
或者您可以让他们在VirtualBox中运行并使用它来限制处理器利用率。
或者,如果他们继续像这样燃烧周期而不是使用某些事件驱动模型或Thread.sleep,则可以解雇他们。

0

0
  1. 代码轮询哪些网站?它们支持RSS推送吗?
  2. 如果它们支持,那么就没有必要轮询这些网站,而是插入一个模块等待更新。当前方法使用wait();进行等待。
  3. 新模块会使用notifyAll()方法通知该对象。
  4. 不可否认,这需要额外的工作,但可以节省大量带宽和计算资源。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接