1

こんにちは私はテキストファイルから読み取り、各行(コンマで分割)を配列に保存しています。唯一の問題は、配列内のほとんどの要素がdouble値であるのに対し、2つの要素は文字列であるということです。この結果、配列をString[]配列にする必要がありました。このため、配列内のdouble値に対していくつかの方程式を実行する場合は、最初にそれらをdouble値として解析する必要があります。私は文字通りこれらの方程式を1000回以上繰り返し実行しているため、コードは常に文字列をdoubleに解析しています。これは私のプログラムを遅くしている費用のかかる方法です。文字列配列の値をdouble値に変換するためのより良い方法はありますか、それともテキストファイルから行を保存するときに取るべきより良い方法はありますか?ありがとう

テキストファイルから読み取った後の配列の1つは次のようになります。

String[] details = {"24.9", "100.0", "19.2" , "82.0", "Harry", "Smith", "45.0"};

ここで、最初の2つの要素を乗算し、それを3番目、4番目、および7番目の要素の合計に追加する必要があります。言い換えれば、私は数値要素(もちろん文字列として保存されている)のみを使用しています

double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]);

テキストファイルの1行ごとにこれを行う必要があります(1000行以上)。この結果、私のプログラムの実行速度は非常に遅くなります。文字列値をdoubleに変換するためのより良い方法はありますか?それとも、そもそもそれらを保存するためのより良い方法はありますか?

編集:私はプロファイラーを使用してコードのどの部分が最も遅いかをチェックしました、そしてそれは確かに私が上に示したコードです

4

2 に答える 2

4

これは、説明したような10000行の入力ファイルを生成し、それを読み戻して、投稿した計算を実行し、結果をstdoutに出力する例です。可能な限り最悪の読み取りパフォーマンスを得るために、ファイルを読み取るときにバッファリングを特に無効にします。他の人が示唆しているように、私もキャッシュをまったく行っていません。ファイルの生成、計算の実行、結果の印刷を含むプロセス全体は、一貫して約520〜550ミリ秒かかります。数百または数千のファイルに対してこの同じプロセスを繰り返さない限り、これはほとんど「遅い」ことではありません。これと大幅に異なるパフォーマンスが見られる場合は、ハードウェアの問題である可能性があります。ハードディスクに障害が発生すると、読み取りパフォーマンスがほとんど低下する可能性があります。

import java.io.*;
import java.util.Random;

public class ReadingDoublesFromFileEfficiency {
    private static Random random = new Random();

    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        String filePath = createInputFile();
        BufferedReader reader = new BufferedReader(new FileReader(filePath), 1);
        String line;
        while ((line = reader.readLine()) != null) {
            String[] details = line.split(",");
            double score = (Double.parseDouble(details[0]) * Double.parseDouble(details[1])) + Double.parseDouble(details[2]) + Double.parseDouble(details[3]) + Double.parseDouble(details[6]);
            System.out.println(score);
        }
        reader.close();
        long elapsed = System.currentTimeMillis() - start;
        System.out.println("Took " + elapsed + " ms");
    }

    private static String createInputFile() throws IOException {
        File file = File.createTempFile("testbed", null);
        PrintWriter writer = new PrintWriter(new FileWriter(file));
        for (int i = 0; i < 10000; i++) {
            writer.println(randomLine());
        }
        writer.close();
        return file.getAbsolutePath();
    }

    private static String randomLine() {
        return String.format("%f,%f,%f,%f,%s,%s,%f",
                score(), score(), score(), score(), name(), name(), score());
    }

    private static String name() {
        String name = "";
        for (int i = 0; i < 10; i++) {
            name += (char) (random.nextInt(26) + 97);
        }
        return name;
    }

    private static double score() {
        return random.nextDouble() * 100;
    }
}
于 2013-03-02T18:02:23.907 に答える
2

適切なオブジェクトを作成し、その中に値を格納することをお勧めします-これにより、2つの大きな利点が得られます。1)二重の値を不必要に再計算することを回避するため、コードが高速になります。何を指しているdetails[0]のか完全に不明確な場所のように電話をかけるのではなく、名前が付けられます。[0]

2)フィールドが何であるかわからないため、クラスは明らかに異なって見えますが、考え方は同じです。

public class PersonScore {
    private double[] multipliers = new double[2];
    private double[] summers = new double[3];
    private String first;
    private String last;

    // expects a parsed CSV String
    public PersonScore(String[] arr) {
        if(arr.length != 7)
            throw new InvalidArgumentException("Must pass exactly 7 fields");
        multipliers[0] = Double.parseDouble(arr[0]);
        multipliers[1] = Double.parseDouble(arr[1]);
        summers[0] = Double.parseDouble(arr[2]);
        summers[0] = Double.parseDouble(arr[3]);
        summers[0] = Double.parseDouble(arr[6]);
        first = arr[4];
        last = arr[5];
    }

    public double score() {
        double ret = 1;
        for(double mult : multipliers)
            ret *= mult;
        for(double sum : summers)
            ret += sum;
        return ret;
    }

    public String toString() {
        return first+" "+last+": "+score();
    }
}

スコアメソッドがより堅牢になったという追加の利点があることに注意してください。上記の実装では、使用したいフィールドをハードコーディングしましたが、フィールドを構造コンテンツとして解析および保存することで、より読みやすく、よりスケーラブルなスコア計算方法を実装できます。

于 2013-03-02T16:58:16.833 に答える