我正在尝试将包含ASCII字符的byte []传递给log4j,以使用明显的表示方式登录到文件中。当我简单地传入byt []时,它当然被视为一个对象,并且日志非常无用。当我尝试使用new String(byte[] data)
将它们转换为字符串时,我的应用程序的性能减半。
如何有效地传递它们,而不会因将它们转换为字符串而造成大约30us的时间损失。
另外,为什么转换它们需要这么长时间?
感谢。
修改
我应该补充一点,我在这里寻找延迟 - 是的,30us确实有所作为!此外,这些数组从~100一直到几千字节不等。
答案 0 :(得分:17)
ASCII是少数几种可以转换为UTF16 /从UTF16转换而无需算术或表查找的编码之一,因此可以手动转换:
String convert(byte[] data) {
StringBuilder sb = new StringBuilder(data.length);
for (int i = 0; i < data.length; ++ i) {
if (data[i] < 0) throw new IllegalArgumentException();
sb.append((char) data[i]);
}
return sb.toString();
}
但要确保它确实 ASCII,否则你最终会变成垃圾。
答案 1 :(得分:14)
你想要做的是延迟处理byte []数组,直到log4j确定它实际上想要记录消息。这样,您可以在DEBUG级别将其记录,例如,在测试期间,然后在生产期间禁用它。例如,您可以:
final byte[] myArray = ...;
Logger.getLogger(MyClass.class).debug(new Object() {
@Override public String toString() {
return new String(myArray);
}
});
现在你不支付速度惩罚,除非你实际记录数据,因为在log4j决定它实际记录消息之前不会调用toString方法!
现在我不确定“明显的表示”是什么意思所以我假设您的意思是通过将字节重新解释为默认字符编码来转换为String。现在,如果你正在处理二进制数据,这显然是毫无价值的。在这种情况下,我建议使用Arrays.toString(byte[])沿
行创建格式化字符串[54, 23, 65, ...]
答案 2 :(得分:8)
如果您的数据实际上是ASCII(即7位数据),那么您应该使用new String(data, "US-ASCII")
而不是依赖于平台默认编码。这可能比尝试将其解释为您的平台默认编码(可能是UTF-8,需要更多内省)更快。
您还可以通过缓存Charset
实例并调用new String(data, charset)
来避免每次Charset-Lookup点击来提高速度。
话虽如此:自从我在生产环境中看到真正的ASCII数据以来,已经很长很长时间了
答案 3 :(得分:1)
答案 4 :(得分:1)
性能减半?这个字节数组有多大?如果它是例如1MB,那么肯定有更多的因素需要考虑,而不仅仅是从字节“转换”到字符(虽然它应该足够快)。 写入 1MB的数据而不是“仅仅”100字节(byte[].toString()
可能生成的)到日志文件显然需要一些时间。磁盘文件系统没有RAM内存那么快。
您需要更改字节数组的字符串表示形式。也许有一些更敏感的信息,例如与之关联的名称(文件名?),长度等等。毕竟,那个字节数组实际代表什么?
修改:我不记得在您的问题中看过“约30us”短语,也许您在询问后的5分钟内进行了编辑,但是这个实际上是微观优化,它一般不应该导致“减半的性能”。除非你每秒写一百万次(那么,你为什么要这样做呢?难道你没有过度使用“记录”现象吗?)。