DecimalFormat.format()的更快替代方法?
为了提高其性能,我一直在使用VisualVM采样器对我的一个应用程序进行性能分析,最小采样周期为20ms。根据探查器,主线程在该DecimalFormat.format()
方法中花费了将近四分之一的CPU时间。
我正在DecimalFormat.format()
与该0.000000
模式一起使用,以将double
数字“转换”
为正好有六个十进制数字的字符串表示形式。我知道这种方法相对昂贵并且 被 多次调用,但是我对这些结果感到有些惊讶。
这种采样分析器的结果在多大程度上准确?我将如何验证它们-最好不借助仪器分析器?
有比
DecimalFormat
我的用例更快的替代方法吗?推出自己的NumberFormat
子类是否有意义?
我创建了一个微基准测试来比较以下三种方法的性能:
DecimalFormat.format()
:单个DecimalFormat
对象多次重复使用。String.format()
:多个独立通话。在内部这种方法可以归结为public static String format(String format, Object ... args) {
return new Formatter().format(format, args).toString();
}
因此,我希望它的性能非常类似于Formatter.format()
。
Formatter.format()
:单个Formatter
对象多次重复使用。
此方法有点尴尬-
Formatter
使用默认构造函数创建的对象会将由该format()
方法创建的所有字符串附加到内部StringBuilder
对象,该内部对象无法正确访问,因此无法清除。结果,多次调用format()
将创建所有结果字符串的
串联 。
要变通解决此问题,我提供了自己的StringBuilder
实例,该实例在与setLength(0)
呼叫一起使用之前已清除。
结果有趣之处:
DecimalFormat.format()
是每次通话1.4us时的基准。String.format()
每次通话2.7us时速度降低了两倍。Formatter.format()
在每次通话时以2.5us的速度降低了两倍。
目前看来,DecimalFormat.format()
在这些替代方案中,它仍然是最快的。
回答:
您可以编写自己的例程,只要您确切知道自己想要什么。
public static void appendTo6(StringBuilder builder, double d) { if (d < 0) {
builder.append('-');
d = -d;
}
if (d * 1e6 + 0.5 > Long.MAX_VALUE) {
// TODO write a fall back.
throw new IllegalArgumentException("number too large");
}
long scaled = (long) (d * 1e6 + 0.5);
long factor = 1000000;
int scale = 7;
long scaled2 = scaled / 10;
while (factor <= scaled2) {
factor *= 10;
scale++;
}
while (scale > 0) {
if (scale == 6)
builder.append('.');
long c = scaled / factor % 10;
factor /= 10;
builder.append((char) ('0' + c));
scale--;
}
}
@Test
public void testCases() {
for (String s : "-0.000001,0.000009,-0.000010,0.100000,1.100000,10.100000".split(",")) {
double d = Double.parseDouble(s);
StringBuilder sb = new StringBuilder();
appendTo6(sb, d);
assertEquals(s, sb.toString());
}
}
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
long start = System.nanoTime();
final int runs = 20000000;
for (int i = 0; i < runs; i++) {
appendTo6(sb, i * 1e-6);
sb.setLength(0);
}
long time = System.nanoTime() - start;
System.out.printf("Took %,d ns per append double%n", time / runs);
}
版画
Took 128 ns per append double
如果您想获得更高的性能,则可以写入直接的ByteBuffer(假设您想将数据写入某处),因此您产生的数据确实需要复制或编码。(假设还可以)
注意:这仅限于小于9万亿(Long.MAX_VALUE / 1e6)的正/负值。如果这可能是一个问题,则可以添加特殊处理。
以上是 DecimalFormat.format()的更快替代方法? 的全部内容, 来源链接: utcz.com/qa/417583.html