2011-04-05 88 views
4

我最近使用JSON来存储一定数量的同一类的子类的配置参数。为了保持一个统一的界面,我提供了父级类别的公共void setParameter(String, String)String getParameter(String)方法。然后,每个子类将提供的参数转换为其本机类型,并使用它们进行某种计算。性能偏执:多少钱Float.parseFloat(String),Integer.parseInt(String)?

现在,我想知道:因为我已经将每个参数存储在一个HashMap中,所以为每个参数保留一个单独的字段和正确类型是否真的有意义?考虑到我需要经常使用它们,每次需要它们时将字符串参数转换为本机类型的计算开销是多少?

谢谢
Tunnuz

+3

你可以测量它吗? – 2011-04-05 08:18:34

+1

您也可以使用Float.valueOf()而不是Float.parseFloat()它会提高性能,因为它使用简单的缓存。 – bvk256 2011-04-05 08:30:40

+2

@ bvk256:Float.valueOf不执行任何缓存。 javadoc认为它确实如此,但是如果您查看源代码(至少在Sun JDK中),它不会。它只是一个新的例子。整数类型的valueOf方法可以做,但不是浮点类型。 – 2011-04-05 08:44:44

回答

5

我建议你测试。如果你需要这么做很多次,但是如果你使用它们来创建数据,那么这个操作相对昂贵,但可以比Double.toString()或Integer.toString()更便宜。

我也建议你只使用double,除非你知道使用float永远不会导致舍入问题。 ;)

它和创建对象一样昂贵,比如String或向HashMap添加条目。除非你打算避免这样做,否则我不会担心。

编辑:于@Stackers'基准类似我会运行测试时间更长,使用nanoTime()

int runs = 10000000; 
String val = "" + Math.PI; 
long start = System.nanoTime(); 
for (int i = 0; i < runs; i++) 
    Float.parseFloat(val); 
long time = (System.nanoTime() - start)/runs; 
System.out.println("Average Float.parseFloat() time was " + time + " ns."); 

long start2 = System.nanoTime(); 
for (int i = 0; i < runs; i++) 
    Double.parseDouble(val); 
long time2 = (System.nanoTime() - start2)/runs; 
System.out.println("Average Double.parseDouble() time was " + time2 + " ns."); 

打印

Average Float.parseFloat() time was 474 ns. 
Average Double.parseDouble() time was 431 ns. 

BTW:我有函数读取从直接ByteBuffer双打这需要80纳秒。速度更快,因为它不需要字符串,也不会创建任何对象。然而,这样做并不是微不足道的,你必须设计你的核心系统来避免任何对象的创建。 )

3

测量一样简单:

public class PerfTest { 
    public static void main(String[] args) { 
     String val = "" + (float) Math.PI; 
     long start = System.currentTimeMillis(); 
     for (int i = 0 ; i < 100000 ; i++) { 
      Float.parseFloat(val); 
     } 
     System.out.println(System.currentTimeMillis() - start + " ms."); 
    } 
} 

62ms为100.000迭代。

+1

+1:我会延长测试时间,例如至少多秒,使用nanoTime()并打印平均时间。 – 2011-04-05 08:39:29

+0

然后在开始真正的测量之前做一个干运行,所以你没有测量任何JIT开销。编辑: – pauluss86 2013-02-22 11:10:42

+0

...把​​你的基准测试放在一个单独的函数中(使用@PeterLawrey的nanoTime()建议和1000万次迭代)并且调用它两次,第一次运行比我慢速x86上网本上的第二次运行要慢(〜20%)。 – pauluss86 2013-02-22 11:17:43

3

上面的microbenchmarks似乎有点不安全,你会期待热点发现val永不会改变&永远不会被使用。另一件需要记住的是,有时候平均值(2个实现)的平均值可能以绝对值相近,但其中1的尾部成本相对于另一个是相当差的,例如,您的第90百分位值可能非常相似,但最后的10%更差。

例如,将其更改为每次使用不同的值并将值转储到stderr会在我的包装箱上产生较高的平均成本(对于重新使用该值的情况,约3300ns vs〜2500ns)。这大大高于其他帖子,可能是因为它需要一些时间才能真正获得时间,因此测量值被人为夸大了。这只是表明了做一个好的微基准的困难之一。

也可能值得注意的是,我无法衡量我建议可能存在的效果,例如,如果它存在,那么你可能会期望它完全被优化掉。我想你可以通过LogCompilation看看发生了什么,如果你真的很热衷。

int runs = 10000000; 
    long totalTime = 0; 
    for (int i = 0; i < runs; i++) { 
     String val = "" + Math.random(); 
     long start = System.nanoTime(); 
     float f = Float.parseFloat(val); 
     long end = System.nanoTime(); 
     System.err.println(f); 
     totalTime += (end-start); 
    } 
    long time = totalTime/runs; 
    totalTime = 0; 
    for (int i = 0; i < runs; i++) { 
     String val = "" + Math.random(); 
     long start = System.nanoTime(); 
     double d = Double.parseDouble(val); 
     long end = System.nanoTime(); 
     System.err.println(d); 
     totalTime += (end-start); 
    } 
    long time2 = totalTime/runs; 
    System.out.println("Average Float.parseFloat() time was " + time + " ns."); 
    System.out.println("Average Double.parseDouble() time was " + time2 + " ns."); 
相关问题