20

私は現在、文字列連結オプションと、それらが全体的なパフォーマンスに与えるペナルティを調べています。そして、私のテストケースは私の心を打つ結果を生み出します、私が何かを見落としているかどうかはわかりません。

取引は次のとおりです。Javaで実行すると、(コンパイル時に)これが実行されるたび"something"+"somethingElse"に新しいものが作成されます。StringBuilder

私のテストケースでは、1661行のサンプルデータ(従来の「LoremIpsum」)を含むファイルをHDDからロードしています。この質問は、I / Oパフォーマンスに関するものではなく、さまざまな文字列連結メソッドのパフォーマンスに関するものです。

public class InefficientStringConcat {

    public static void main(String[] agrs) throws Exception{
        // Get a file with example data:

        System.out.println("Starting benchmark");
        // Read an measure:
        for (int i = 0; i < 10; i++){
            BufferedReader in = new BufferedReader(
                    new InputStreamReader(new FileInputStream(new File("data.txt")))
            );

            long start = System.currentTimeMillis();
            // Un-comment method to test:
            //inefficientRead(in);
            //betterRead(in);
            long end = System.currentTimeMillis();
            System.out.println("Took "+(end-start)+"ms");

            in.close();
        }



    }

    public static String betterRead(BufferedReader in) throws IOException{
        StringBuilder b = new StringBuilder();
        String line;
        while ((line = in.readLine()) != null){
            b.append(line);
        }
        return b.toString();
    }

    public static String inefficientRead(BufferedReader in) throws IOException {
        String everything = "", line;
        while ((line = in.readLine()) != null){
            everything += line;
        }
        return everything;
    }
}

ご覧のとおり、セットアップは両方のテストで同じです。結果は次のとおりです。

inefficientRead()-methodの使用:

Starting benchmark
#1 Took 658ms
#2 Took 590ms
#3 Took 569ms
#4 Took 567ms
#5 Took 562ms
#6 Took 570ms
#7 Took 563ms
#8 Took 568ms
#9 Took 560ms
#10 Took 568ms

-methodを使用するbetterRead()

Starting benchmark
#1 Took 42ms
#2 Took 10ms
#3 Took 5ms
#4 Took 7ms
#5 Took 16ms
#6 Took 3ms
#7 Took 4ms
#8 Took 5ms
#9 Took 5ms
#10 Took 13ms

-コマンドに追加のパラメーターを追加せずにテストを実行していますjava2009年初頭からMacMini3,1とSunJDK7を実行しています。

[luke@BlackBox ~]$ java -version
java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) Client VM (build 23.5-b02, mixed mode)

これは非常に大きな違いだと思います。私はこれを測定する際に何か間違ったことをしていますか、それともこれが起こるはずですか?

4

2 に答える 2

25

これを測定する際に何か間違ったことをしていますか、それとも起こるはずですか?

それは起こるはずです。文字列の連結を繰り返し使用して長い文字列を作成することは、既知のパフォーマンス アンチパターンです。すべての連結では、元の文字列のコピーと追加の文字列のコピーを使用して新しい文字列を作成する必要があります。O(N 2 ) のパフォーマンスが得られます。を使用する場合、ほとんどの場合、追加の文字列をバッファーにコピーするだけです。場合によっては、バッファーのスペースが不足し、(既存のデータを新しいバッファーにコピーすることによって) 拡張する必要がありますが、それは頻繁には起こりません (バッファー拡張戦略のため)。StringBuilder

詳細については、文字列連結に関する私の記事を参照してください。これは非常に古い記事であるため、 predatesStringBuilderですが、基本は変更されていません。(基本的StringBuilderには に似StringBufferていますが、同期はありません。)

于 2013-03-02T18:42:19.660 に答える
6

これはまさに起こるべきことです。 betterRead線形時間がかかります。inefficientRead二次時間がかかります。

于 2013-03-02T18:42:05.220 に答える