我正在为二进制数据开发基于Java的下载程序。该数据通过基于文本的协议(UU编码)传输。对于网络任务,使用 netty 库。二进制数据由服务器分成数千个小数据包并发送到客户端(即Java应用程序)。
从 netty 每次收到新消息(数据)时,我都会收到一个ChannelBuffer
对象。现在我需要处理这些数据,除了我需要检查来自服务器的包的头部的其他任务(比如HTTP状态行)。为此,我致电ChannelBuffer.array()
以接收byte[]
数组。然后,我可以通过new String(byte[])
将此数组转换为字符串,并轻松检查(例如比较)其内容(再次,与HTTP中的“200”状态消息进行比较)。
我正在编写的软件使用多个线程/连接,因此我可以并行收到来自 netty 的多个数据包。
这通常可以正常工作,但是,在分析应用程序时,我注意到当与服务器的连接良好且数据进入非常快时,这种转换到String
对象似乎是一个瓶颈。在这种情况下,CPU使用率接近100%,并且根据分析器,在调用此String(byte[])
构造函数时花费了很多时间。
我搜索了从ChannelBuffer
到String
的更好方法,并注意到前者也有toString()
方法。但是,该方法甚至比String(byte[])
构造函数慢。
所以我的问题是:你们中有谁知道一个更好的选择来实现我的目标吗?
答案 0 :(得分:15)
也许你可以完全跳过String转换?你可以让常量为你的比较值保存字节数组,并检查数组到数组而不是字符串到字符串。
这里有一些快速代码来说明。目前你正在做这样的事情:
String http200 = "200";
// byte[] -> String conversion happens every time
String input = new String(ChannelBuffer.array());
return input.equals(http200);
也许这更快:
// Ideally only convert String->byte[] once. Store these
// arrays somewhere and look them up instead of recalculating.
final byte[] http200 = "200".getBytes("UTF-8"); // Select the correct charset!
// Input doesn't have to be converted!
byte[] input = ChannelBuffer.array();
return Arrays.equals(input, http200);
答案 1 :(得分:2)
您正在进行的一些检查可能只是查看部分缓冲区。如果您可以使用String构造函数的替代形式:
new String(byteArray, startCol, length)
这可能意味着将更少的字节转换为字符串。
你在信息中寻找“200”的例子就是一个例子。
<强> 2 强>
您可能会发现可以使用字节数组的长度作为线索。如果某些消息很长并且您正在寻找一个短消息,请忽略长消息并且不要转换为字符。或类似的东西。
第3 强>
除了@EricGrunzke所说的,部分查看字节缓冲区以过滤掉一些消息并发现你不需要将它们从字节转换为字符。
<强> 4 强>
如果你的字节是ASCII字符,如果使用charset“ASCII”而不是服务器的默认值,转换为字符的速度可能会更快:
new String(bytes, "ASCII")
在这种情况下,可能会更快。
事实上,您可以通过某种有组织的方式选择转换字节字符的字符集,从而加快速度。
答案 2 :(得分:0)
根据您的尝试,有以下几种选择:
字符串转换的最大成本很可能是将数据从字节数组复制到String的内部char数组,这与转换相结合很可能只是一堆你不需要的工作要做。