2011-04-05 23 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."); 
相關問題