簡體   English   中英

Java中StringTokenizer類與String.split方法的性能

[英]Performance of StringTokenizer class vs. String.split method in Java

在我的軟件中,我需要將字符串分成單詞。 我目前擁有超過19,000,000個文檔,每個文檔超過30個單詞。

以下哪兩種方法是最好的方法(在性能方面)?

StringTokenizer sTokenize = new StringTokenizer(s," ");
while (sTokenize.hasMoreTokens()) {

要么

String[] splitS = s.split(" ");
for(int i =0; i < splitS.length; i++)

如果您的數據已經在數據庫中,您需要解析字符串,我建議重復使用indexOf。 它比任何一種解決方案快很多倍。

但是,從數據庫獲取數據仍然可能要昂貴得多。

StringBuilder sb = new StringBuilder();
for (int i = 100000; i < 100000 + 60; i++)
    sb.append(i).append(' ');
String sample = sb.toString();

int runs = 100000;
for (int i = 0; i < 5; i++) {
    {
        long start = System.nanoTime();
        for (int r = 0; r < runs; r++) {
            StringTokenizer st = new StringTokenizer(sample);
            List<String> list = new ArrayList<String>();
            while (st.hasMoreTokens())
                list.add(st.nextToken());
        }
        long time = System.nanoTime() - start;
        System.out.printf("StringTokenizer took an average of %.1f us%n", time / runs / 1000.0);
    }
    {
        long start = System.nanoTime();
        Pattern spacePattern = Pattern.compile(" ");
        for (int r = 0; r < runs; r++) {
            List<String> list = Arrays.asList(spacePattern.split(sample, 0));
        }
        long time = System.nanoTime() - start;
        System.out.printf("Pattern.split took an average of %.1f us%n", time / runs / 1000.0);
    }
    {
        long start = System.nanoTime();
        for (int r = 0; r < runs; r++) {
            List<String> list = new ArrayList<String>();
            int pos = 0, end;
            while ((end = sample.indexOf(' ', pos)) >= 0) {
                list.add(sample.substring(pos, end));
                pos = end + 1;
            }
        }
        long time = System.nanoTime() - start;
        System.out.printf("indexOf loop took an average of %.1f us%n", time / runs / 1000.0);
    }
 }

版畫

StringTokenizer took an average of 5.8 us
Pattern.split took an average of 4.8 us
indexOf loop took an average of 1.8 us
StringTokenizer took an average of 4.9 us
Pattern.split took an average of 3.7 us
indexOf loop took an average of 1.7 us
StringTokenizer took an average of 5.2 us
Pattern.split took an average of 3.9 us
indexOf loop took an average of 1.8 us
StringTokenizer took an average of 5.1 us
Pattern.split took an average of 4.1 us
indexOf loop took an average of 1.6 us
StringTokenizer took an average of 5.0 us
Pattern.split took an average of 3.8 us
indexOf loop took an average of 1.6 us

打開文件的成本約為8毫秒。 由於文件太小,您的緩存可能會將性能提高2-5倍。 即使如此,它將花費大約10個小時打開文件。 使用split vs StringTokenizer的成本遠低於0.01 ms。 解析1900萬x 30個單詞*每個單詞8個字母大約需要10秒鍾(每2秒約1 GB)

如果你想提高性能,我建議你有更少的文件。 例如,使用數據庫。 如果您不想使用SQL數據庫,我建議使用其中一個http://nosql-database.org/

在Java 7中拆分只是為此輸入調用indexOf, 請參閱源代碼 拆分應該非常快,接近indexOf的重復調用。

Java API規范建議使用split 請參閱StringTokenizer文檔

另一個重要的事情,據我注意到,沒有記錄,要求StringTokenizer返回分隔符和標記化字符串(通過使用構造函數StringTokenizer(String str, String delim, boolean returnDelims) )也減少了處理時間。 所以,如果你正在尋找性能,我建議使用類似的東西:

private static final String DELIM = "#";

public void splitIt(String input) {
    StringTokenizer st = new StringTokenizer(input, DELIM, true);
    while (st.hasMoreTokens()) {
        String next = getNext(st);
        System.out.println(next);
    }
}

private String getNext(StringTokenizer st){  
    String value = st.nextToken();
    if (DELIM.equals(value))  
        value = null;  
    else if (st.hasMoreTokens())  
        st.nextToken();  
    return value;  
}

盡管getNext()方法引入了開銷,但是丟棄了分隔符,根據我的基准測試,它仍然快50%。

使用拆分。

StringTokenizer是一個遺留類,出於兼容性原因而保留,盡管在新代碼中不鼓勵使用它。 建議任何尋求此功能的人都使用split方法。

在運行micro(在這種情況下甚至納米)基准測試時,會有很多因素影響您的結果。 JIT優化和垃圾收集僅舉幾例。

為了從微基准測試中獲得有意義的結果,請查看jmh庫。 它有很好的樣本捆綁在如何運行良好的基准測試。

19,000,000份文件必須在那里做什么? 你是否必須定期在所有文件中分詞? 或者這是一個拍攝問題?

如果您一次顯示/請求一個文檔,只有30個單詞,這是一個非常小的問題,任何方法都可以工作。

如果你必須一次處理所有文件,只有30個單詞,這是一個非常小的問題,你最好還是IO綁定。

無論遺留狀態如何,我都希望StringTokenizerString.split()明顯更快,因為它不使用正則表達式:它只是直接掃描輸入,就像你自己通過indexOf() 事實上,每次調用時, String.split()都必須編譯正則表達式,因此它甚至不如直接使用正則表達式那樣高效。

這可能是使用1.6.0的合理基准測試

http://www.javamex.com/tutorials/regular_expressions/splitting_tokenisation_performance.shtml#.V6-CZvnhCM8

性能明智的StringTokeniser比split更好。 檢查下面的代碼,

在此輸入圖像描述

但根據Java文檔,它的使用是不鼓勵的。 檢查一下

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM