14

我正在为二进制数据开发一个基于 Java 的下载器。该数据通过基于文本的协议(UU 编码)传输。对于网络任务,使用netty库。服务器将二进制数据拆分成数千个小数据包并发送到客户端(即 Java 应用程序)。

每次收到新消息(数据)时,我都会从netty收到一个对象。ChannelBuffer现在我需要处理这些数据,除了其他任务我需要检查来自服务器的包的标题(如 HTTP 状态行)。为此,我调用ChannelBuffer.array()接收byte[]数组。然后我可以将该数组转换为字符串,new String(byte[])并轻松检查(例如比较)其内容(再次,如与 HTTP 中的“200”状态消息进行比较)。

我正在编写的软件使用多个线程/连接,以便我从netty并行接收多个数据包。

这通常可以正常工作,但是,在分析应用程序时,我注意到当与服务器的连接良好且数据输入速度非常快时,这种到String对象的转换似乎是一个瓶颈。在这种情况下,CPU 使用率接近 100%,并且根据分析器,在调用此String(byte[])构造函数时会花费大量时间。

我寻找一种更好的方法来从ChannelBuffer到 a String,并注意到前者也有一种toString()方法。但是,该方法甚至比String(byte[])构造函数还要慢。

所以我的问题是:你们中的任何人都知道实现我正在做的事情的更好选择吗?

4

3 回答 3

16

也许您可以完全跳过字符串转换?您可以使用常量来保存比较值的字节数组,并检查数组到数组而不是字符串到字符串。

这里有一些快速代码来说明。目前你正在做这样的事情:

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);
于 2013-10-11T19:48:21.177 回答
2

您正在进行的某些检查可能只查看缓冲区的一部分。如果您可以使用 String 构造函数的替代形式:

new String(byteArray, startCol, length)

这可能意味着更少的字节被转换为字符串。

您在消息中查找“200”的示例就是一个示例。

2

您可能会发现可以使用字节数组的长度作为线索。如果某些消息很长而您正在寻找短消息,请忽略长消息并且不要转换为字符。或类似的东西。

3

随着@EricGrunzke 所说,部分查看字节缓冲区以过滤掉一些消息并发现您不需要将它们从字节转换为字符。

4

如果您的字节是 ASCII 字符,那么如果您使用 charset "ASCII" 而不是服务器的默认值,则转换为字符可能会更快:

new String(bytes, "ASCII")

在这种情况下可能会更快。

事实上,您可能能够以某种有条理的方式来挑选字符集来转换字节字符,从而加快速度。

于 2013-10-11T19:56:02.073 回答
0

根据您要执行的操作,有几个选项:

  1. 如果您只是想获得响应状态,那么您不能只调用getStatus()吗?这可能比取出字符串要快。
  2. 如果您尝试转换缓冲区,那么,假设您知道它将是 ASCII,这听起来像您所做的那样,那么只需将数据保留为 byte[] 并将您的 UUDecode 方法转换为处理 byte[] 而不是细绳。

字符串转换的最大成本很可能是将数据从字节数组复制到字符串的内部字符数组,这与转换相结合很可能只是一堆你不需要做的工作。

于 2013-10-11T19:59:42.603 回答