Java中高效的strod?

Java中高效的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

所以我有一个Java程序,我用它来咀嚼数TB的数据。性能是一个问题

我已经分析了该应用程序,所有内存分配的很大一部分以及CPU时间的很大一部分都来自于执行一个简单的操作:

我有一个ASCII字符数组。我知道从offset
I
到offset
j
的字符代表一个浮点数。我需要将那个浮点数提取成一个
双精度

简单的
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
实现?来自此链接: