Java中高效的strod?
所以我有一个Java程序,我用它来咀嚼数TB的数据。性能是一个问题 我已经分析了该应用程序,所有内存分配的很大一部分以及CPU时间的很大一部分都来自于执行一个简单的操作: 我有一个ASCII字符数组。我知道从offsetJava中高效的strod?,java,string,performance,memory,floating-point,Java,String,Performance,Memory,Floating Point,所以我有一个Java程序,我用它来咀嚼数TB的数据。性能是一个问题 我已经分析了该应用程序,所有内存分配的很大一部分以及CPU时间的很大一部分都来自于执行一个简单的操作: 我有一个ASCII字符数组。我知道从offsetI到offsetj的字符代表一个浮点数。我需要将那个浮点数提取成一个双精度 简单的Double.parseDouble(新字符串(buf,i,j-i))完成这项工作。但是,这是花费大量时间和分配大量内存的地方,可能是因为: newstring()创建一个新对象,创建一个内部ch
I
到offsetj
的字符代表一个浮点数。我需要将那个浮点数提取成一个双精度
简单的Double.parseDouble(新字符串(buf,i,j-i))
完成这项工作。但是,这是花费大量时间和分配大量内存的地方,可能是因为:
newstring()
创建一个新对象,创建一个内部char[]
数组
并将字符复制到数组中李>
Double.parseDouble()
创建一个对象,也创建一个char[]
数组,
还将字符复制到其中
所有这些分配和所有这些复制都不是真正必要的。我能避开它们吗
我真正想要的是一个类函数,它将接受一个char[]
(或一个byte[]
)以及开始/结束偏移量,并返回一个double
有什么建议吗?我应该推出自己的吗?我应该在strtod附近写一个JNI包装器吗?我应该使用一些已经存在的Java库吗?我会查看Java.lang.Double
的源代码,将执行parseDouble
的代码复制到我自己的助手类中,并将其修改为使用offset
和length
直接处理char[]
,您可以使用JNI为它编写一个包装器。我过去所做的是为ByteBuffer(避免字节到字符的编码转换)编写一个双精度解析器,反之亦然。如果可以避免创建任何对象,那么创建速度会快得多。这种方法适用于内存映射文件,也避免了一些复制成本
核心代码如下所示。它不处理指数,但您可以添加它
@Override
public double read() throws BufferUnderflowException {
long value = 0;
int exp = 0;
boolean negative = false;
int decimalPlaces = Integer.MIN_VALUE;
while (true) {
byte ch = buffer.get();
if (ch >= '0' && ch <= '9') {
while (value >= MAX_VALUE_DIVIDE_10) {
value >>>= 1;
exp++;
}
value = value * 10 + (ch - '0');
decimalPlaces++;
} else if (ch == '-') {
negative = true;
} else if (ch == '.') {
decimalPlaces = 0;
} else {
break;
}
}
return asDouble(value, exp, negative, decimalPlaces);
}
@覆盖
public double read()引发BufferUnderflowException{
长值=0;
int exp=0;
布尔负=假;
int decimalPlaces=Integer.MIN_值;
while(true){
字节ch=buffer.get();
如果(ch>='0'&&ch=MAX\u VALUE\u DIVIDE\u 10){
值>>=1;
exp++;
}
值=值*10+(ch-“0”);
小数位数++;
}else if(ch='-'){
负=真;
}else if(ch='.')){
小数位数=0;
}否则{
打破
}
}
返回为double(值、exp、负数、小数位数);
}
当它得到它不期望的任何字节时,它就会停止,例如、
或\n
出于好奇,我将strtod函数复制到Java中,与Double.parseDouble(String)方法相比,它的速度提高了约10倍(即使在循环中没有创建新字符串)。但这对于您的实现来说可能还不够
微观基准测试提供:
Double.parseDouble():1.6M转换/秒
Java strtod()方法:10.5M转换/秒这是一个选项,除了这基本上是FloatingDecimal
所做的,大约有3K行代码,大量内存分配分散在各处。如果我能帮上忙的话,不要真的喜欢黑客攻击(JNI路由听起来更吸引人)。实际上,String.substring方法不会复制初始数组。如果字符串构造函数是一个瓶颈,它可能会很有用。不过,您可能会增加JNI开销(我假设会有一些成本)。如果它是一个静态函数,那么开销可能相当合理。找到答案的唯一方法就是尝试!(+1)太棒了,谢谢你这么做。出于兴趣,您采用了哪种strod
实现?来自此链接: