2011-09-07 76 views
5

所以我有這個Java程序,我用它來通過幾TB的數據。性能是一個問題。Java中的高效strtod?

我異形的應用程序,所有內存分配的很大一部分,以及CPU時間的很大一部分來自於執行一個簡單的操作:

我有ASCII字符數組。我知道從偏移量i到偏移量j的字符表示一個浮點數。我需要將該浮點數字提取爲double

天真Double.parseDouble(new String(buf, i, j - i))完成這項工作。然而,這是很多的時間都花在和大量的內存分配來的,可能是因爲:

  • new String()創建一個新對象,創建一個內部char[]陣列 並拷貝到字符數組;
  • Double.parseDouble() 創建一個FloatingDecimal對象,也創建一個char[]數組, 也將字符複製到它。

所有這些分配和所有這些複製並不是真的有必要。我能避免它們嗎?

我真正喜歡的是一個strtod樣的功能,將採取一個char[](或byte[]),以及開始/結束偏移,並返回一個double

有什麼建議嗎?我應該推出自己的?我應該在strtod周圍寫一個JNI包裝嗎?我應該使用一些已經存在的Java庫嗎?

+0

其實,String.substring方法不會複製初始數組。如果String構造函數是一個瓶頸,它可能會很有用。 –

回答

5

我過去所做的是爲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); 
} 

The full code

它一旦它得到它並不如期望的任何字節停止一個,\n

+0

(+1)不錯,謝謝分享! – NPE

+0

還有一個將雙精度編碼爲ByteBuffer的代碼。 –

5

我想看看源java.lang.Double,但這parseDouble將代碼複製出我自己的助手,並修改它直接offsetlengthchar[]工作。

+0

這是一個選項,只是這基本上是FloatingDecimal所做的,它大約有大約3K行代碼,並且分佈有大量內存分配。如果我可以幫到它,那麼不要幻想黑客攻擊(JNI路線聽起來更吸引人)。 – NPE

1

如果你知道一個高效的C實現,你可以用JNI爲它編寫一個包裝器。

+0

雖然你會添加JNI的開銷(我認爲有一些成本)。 – Thilo

+0

如果它是一個靜態函數,則開銷可能相當合理。找出答案的唯一方法就是試試! –

2

出於好奇,我複製的strtod功能到Java,並獲得約10時加速比較傳遞給Double.parseDouble(String)方法(即使沒有循環創建新的字符串)。但是,這對於您的實施來說可能不夠。

微標杆給出:

Double.parseDouble():1.6M轉換/秒
的Java關於strtod()方法:10.5M轉換/秒

+0

(+1)非常好,謝謝你這樣做。出於興趣,你採取了哪些「實施」的方式? – NPE

+1

來自此鏈接:[http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/missing/strtod.c](http://svn.ruby-lang.org/repos/ruby/branches /ruby_1_8/missing/strtod.c) – styken