使用 StringBuilder 的 Java CLI 应用程序性能
一般:
我正在编写一个套接字客户端,它始终从某个服务器端(远程服务器端)接收“市场”数据/报价(永无止境的循环)。
我将数据分成块,以便我可以使用它。
每个块大约包含200个字符,需要转换为数组。
块被划分后,它被解析成一个列表(这里没有问题)。
问题:
运行10分钟后CPU使用率达到40%。
我已成功隔离问题。
每个块都需要转换为json。
所以我现在给你解决问题的实际代码。
此代码每 300-400 MS 执行一次。
跳过此代码将使整个系统的 CPU 使用率保持在 1%-2%。
注意:
我已阅读此线程,但我没有看到任何解决方案。
在循环中重用 StringBuilder 是否更好?
代码:
private static StringBuffer jsonVal = new StringBuffer();
public static String toJson(List<QuotesData> quotesData) {
// Empty variable
jsonVal.delete(0, jsonVal.length());
jsonVal.append("{");
synchronized (quotesData) {
for (QuotesData quote : quotesData) {
jsonVal.append("\"").append(quote.getSymbol()).append("\":[{");
jsonVal.append("\"ask\":\"").append(quote.getAsk()).append(
"\",");
jsonVal.append("\"bid\":\"").append(quote.getBid()).append(
"\",");
jsonVal.append("\"time\":\"").append(quote.getDateTime())
.append("\"}],");
}
jsonVal.append("}");
String returnString = jsonVal.toString();
return returnString.toString().replace("}],}", "}]}");
}
}
General:
I am writing a socket client that receives "Market" data/quotes all the time (never ending loop) from some server side (distant one).
i am dividing the data in to chunks so i can use it.
each chunk contains about 200 characters and needs to be converted in to an array.
After a chunk was divided it is been parsed in to a List (No Problems here).
The problem:
The CPU usage is reaching to 40% after 10 minutes of running.
I have managed to isolate the problem.
Every chunk needs to be converted in to json.
So i am giving you now the actual code that does the problems.
this code executes every 300-400 MS.
skipping this code will leave the entire system with 1%-2% CPU usage.
Note:
I have read this thread but i don't see any solution there.
Is it better to reuse a StringBuilder in a loop?
The code:
private static StringBuffer jsonVal = new StringBuffer();
public static String toJson(List<QuotesData> quotesData) {
// Empty variable
jsonVal.delete(0, jsonVal.length());
jsonVal.append("{");
synchronized (quotesData) {
for (QuotesData quote : quotesData) {
jsonVal.append("\"").append(quote.getSymbol()).append("\":[{");
jsonVal.append("\"ask\":\"").append(quote.getAsk()).append(
"\",");
jsonVal.append("\"bid\":\"").append(quote.getBid()).append(
"\",");
jsonVal.append("\"time\":\"").append(quote.getDateTime())
.append("\"}],");
}
jsonVal.append("}");
String returnString = jsonVal.toString();
return returnString.toString().replace("}],}", "}]}");
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先,我建议使用 JProfiler 或 JConsole(两者都包含在 JDK6 中)来精确定位性能受到影响的位置。
在不知道 CPU 使用情况的情况下,我会避免同步。我怀疑
append
是问题所在。通过删除static
本地jsonVal
来清理它。考虑使用 Gson 等 JSON 库。代码变得更加简单。如果需要,您可以调整输出:
First I would suggest using JProfiler or JConsole, both included in JDK6, to pinpoint exactly where the performance hit is.
Without knowing where the CPU usage is, I would avoid
synchronized
. I doubtappend
is the problem. Clean it up by getting rid of thestatic
localjsonVal
, too.Consider using a JSON library like Gson. The code becomes much simpler. You can tweak the output if needed:
我的客人是 StringBuilder 不断调整大小。有多少个报价数据?我建议您在 for 循环之前创建一个具有大小的 StringBuilder:
顺便说一句,您是否考虑过使用 StringBuilder 来代替?它与 StringBuffer 相同,减去线程安全的开销(StringBuffer 是同步的,StringBuild 不是)。
My guest is that StringBuilder is constantly being resized. How many quotesData there is? I suggest you create a StringBuilder with a size before the for loop:
By the way, have you considered using StringBuilder instead? It's the same as StringBuffer, minus the overhead of being thread-safe (StringBuffer is synchronized, StringBuild is not).
好的,这看起来像是过度优化的典型案例。
对象创建并不那么昂贵,您需要重写相同的字符串缓冲区,特别是如果每 300-400 毫秒调用一次。
我将尝试解决所有可能的情况:
指数增长
上面的代码每 300 毫秒分配给一个新线程,但列表非常庞大,需要超过 300 毫秒才能序列化。如果是这种情况,您基本上会阻塞您的资源,应用程序崩溃只是时间问题。
如果是这种情况,您应该会看到 CPU 不断上升。
解决方案是:
加速
好的,所以列表是不可克隆的,我假设这意味着它不是真正的列表,而是作为列表接口实现的某种队列。因此,保持同步不变,我会这样做:
大多数更改都是装饰性的,并且我非常确定 JIT 已经对它们进行了优化。我要做的唯一区别是使用 StringBuilder 并每次创建一个新的,而不是使用 .replace()。
但为了进一步强调我的观点,除非你符合第一个描述(指数增长),否则我怀疑问题就在这里。我会先看看你列出的实施情况。
OK, so this looks like a classic case of over optimization.
Object creation isn't that expensive that you need to rewrite the same string buffer, especially if this is called every 300-400ms.
I'll try to address every possible scenario:
Exponential growth
The above code is assigned to a new thread every 300ms but the list is enormous and takes over 300ms to serialize. If this is the case you are basically choking your resources and it is only a matter of time before the application crashes.
If this is the case, you should see the CPU constantly rising.
The solution would be to:
Speedups
OK, so the list isn't clonable which I'm assuming means it isn't really a list but rather some sort of queue implemented as a list interface. So leaving synchronization as is I would do this:
Most of the changes are cosmetic, and I'm pretty sure that the JIT would already optimize them. Only difference I would do is use StringBuilder and create a new one each time and don't use .replace().
But to stress my point further unless you fit the first description (exponential growth) I doubt the problem is here. I would look at you list implementation first.
一些建议:
StringBuilder
而不是StringBuffer
。StringBuffer
是同步的,StringBuilder
不是。synchronized
语句真的需要吗?如果没有,请尝试将其删除。toString()
。您可以将其删除。replace()
方法,如果returnString
很长,那么成本可能会很高。返回 returnString.intern()
A few suggestions:
StringBuilder
instead ofStringBuffer
.StringBuffer
is synchronized,StringBuilder
is not.synchronized
statement really needed? If not, try removing it.toString()
is not needed on the return statement. You can remove it.replace()
method in the end, that could be costly ifreturnString
is long.StringBuffer
object before the loop instead clearing of the old one.return returnString.intern()