Java:比String(byte [])更快的替代方案

14

我正在开发一个基于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[])构造函数更慢。

因此,我的问题是:你们中有谁知道实现我的目标的更好的替代方案吗?


为什么?尽可能快地发送字节即可。忘记uuencoding;忘记分割。TCP已经进行了分割,并且它比您更了解当前连接上的最佳数据包大小。 - user207421
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);

1
+1 创建字符串可能比你预期的更耗费资源。避免创建它们可以显著提高性能。 - Peter Lawrey

2

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

new String(byteArray, startCol, length)

那可能意味着更少的字节被转换为字符串。
例如,您要在消息中查找“200”。
您可能会发现,您可以使用字节数组的长度作为提示。如果某些消息很长,而您正在查找短消息,则忽略长消息并且不要将其转换为字符。或者类似的操作。
除了@EricGrunzke所说的内容之外,部分地查看字节缓冲区以过滤一些消息,并发现您不需要将它们从字节转换为字符。
如果您的字节是ASCII字符,则使用charset“ASCII”而不是服务器上默认的字符集可能会更快地将其转换为字符。
new String(bytes, "ASCII")

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

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


0

根据您想要做什么,有几个选项:

  1. 如果您只是想获取响应状态,那么不能直接调用getStatus()吗?这可能比获取字符串更快。
  2. 如果您想要转换缓冲区,那么假设您知道它将是ASCII码,就像您所说的那样,那么只需将数据保留为byte[],并将您的UUDecode方法转换为在byte[]上工作而不是在String上工作。

字符串转换的最大成本很可能是从字节数组复制数据到String的内部字符数组,加上转换可能只是一些您不需要做的工作。


为什么#2只能在ASCII下工作?byte[]不能包含非ASCII字符(如UTF-8、UTF-16)吗? - shibel
@shibel 当然,byte[] 可以是任何二进制数据。然而,如果你想要从 UTF-8 进行转换,那么如果你将其保留为字节数组,则需要自己处理该编码。然而,鉴于它们具有 UUEncoded 数据,我们知道它是 ASCII,并且 byte == char。 - Paul Wagland

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