常规
我正在编写一个套接字客户端,它从一些服务器端(远程的)接收“市场”数据/引用(永不结束循环)。
我正在将数据分成块,以便我可以使用它
每个块包含大约200个字符,需要转换为数组
分块后,它被解析为List(这里没有问题)。
问题:
运行10分钟后CPU使用率达到40%
我设法解决了这个问题
每个块都需要转换为json
所以我现在给你解决问题的实际代码
此代码每300-400 MS执行一次
跳过此代码将使整个系统的CPU使用率降低1%-2%。
注意:的
我已经读过这个帖子,但我没有看到任何解决方案
Is it better to reuse a StringBuilder in a loop?
代码:
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("}],}", "}]}");
}
}
答案 0 :(得分:2)
首先,我建议使用JDK6中包含的JProfiler或JConsole来精确地确定 的性能。
在不知道CPU使用情况的地方,我会避免使用synchronized
。我怀疑append
是个问题。通过摆脱static
本地jsonVal
来清理它。
public static String toJson(final List<QuotesData> quotesData) {
final List<QuotesData> theData = new ArrayList<QuotesData>(quotesData);
StringBuffer jsonVal = new StringBuffer();
jsonVal.append("{");
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("}],}", "}]}");
}
考虑使用像Gson这样的JSON库。代码变得更加简单。如果需要,您可以调整输出:
private static final Gson gson = new Gson();
public static String toJson(final List<QuotesData> quotesData) {
return gson.toJson(new ArrayList<QuoteData>(quotesData));
}
答案 1 :(得分:0)
一些建议:
StringBuilder
代替StringBuffer
。 StringBuffer
已同步,StringBuilder
未同步。synchronized
声明吗?如果没有,请尝试将其删除。toString()
。你可以删除它。replace()
方法,如果returnString
很长,则代价可能会很高。StringBuffer
对象,而不是清除旧的。{/ li>
return returnString.intern()
答案 2 :(得分:0)
我的客人是StringBuilder不断调整大小。有多少引号数据?我建议你在for循环之前创建一个大小的StringBuilder:
StringBuffer jsonVal = new StringBuffer(quotesData.size()*200); //the 200 is on top of my head. Do a few loop to see what is the average length of a QuotesData.
顺便问一下,您是否考虑过使用StringBuilder?它与StringBuffer相同,减去线程安全的开销(StringBuffer是同步的,StringBuild不是)。
答案 3 :(得分:0)
好的,所以这看起来像过度优化的经典案例。 对象创建并不需要重写相同的字符串缓冲区,特别是如果每3到400毫秒调用一次。
我会尝试解决所有可能的情况: 指数增长 上面的代码每300毫秒分配给一个新的线程,但是列表很大,需要300多秒才能序列化。如果是这种情况,您基本上会窒息资源,应用程序崩溃只是时间问题。 如果是这种情况,您应该看到CPU不断上升。 解决方案是:
<强>加速比强> 好的,所以列表不是克隆的,我假设它意味着它不是真正的列表,而是某种实现为列表接口的队列。所以保持同步,我会这样做:
public static final int JSON_LENGTH = 250; //you probably know this
public static String toJson(final List<QuotesData> quotesData) {
jsonVal = new StringBuilder(JSON_LENGTH * quotesData.size());
jsonVal.append("{");
synchronized (quotesData) {
for (QuotesData quote : quotesData) {
jsonVal.append("\"").append(quote.getSymbol()).append("\":[{")
.append("\"ask\":\"").append(quote.getAsk()).append("\",")
.append("\"bid\":\"").append(quote.getBid()).append("\",")
.append("\"time\":\"").append(quote.getDateTime()).append("\"}],");
}
// much much faster than replace
jsonVal.setCharAt(jsonVal.length()-1, '}');
return jsonVal.toString();
}
}
大多数变化都是装饰性的,我很确定JIT已经对它们进行了优化。我唯一的区别是使用StringBuilder并每次创建一个新的,不要使用 .replace()。 但要进一步强调我的观点,除非你符合第一个描述(指数增长),我怀疑问题在这里。我先看看你的列表实现。