0

.csv ファイルから項目を読み取り、それらをリモート データベースに書き込むプログラムを扱っています。プログラムをマルチスレッド化しようとしています。そのために、個別の接続を持つ 2 つのプロセス スレッドを作成しました。この目的のために、.csv ファイルがバッファリングされたリーダーに読み込まれ、バッファリングされたリーダーの内容が処理されます。ただし、スレッドはデータを複製し続けているようです (すべてのタプルの 2 つのコピーをデータベースに書き込みます)。

Java でバッファをミューテックスする方法を見つけようとしてきましたが、思いつく最も近いものはプライオリティ キューです。

私の質問は、バッファ付きリーダーを使用して、ファイルを優先キューに 1 行ずつ読み込むことができるかということです。IE

public void readFile(Connection connection) {
        BufferedReader bufReader = null;
        try{
            bufReader = new BufferedReader(new FileReader(RECS_FILE));
            bufReader.readLine(); //skip header line
            String line;
            while((line = bufReader.readLine()) != null) {
                //extract fields from each line of the RECS_FILE
                Pattern pattern = Pattern.compile( "\"([^\"]+)\",\"([^\"]+)\",\"([^\"]+)\",\"([^\"]+)\"");
                Matcher matcher = pattern.matcher(line); 
                if(!matcher.matches()) {
                    System.err.println("Unexpected line in "+RECS_FILE+": \""+line+"\"");
                    continue;
                }
                String stockSymbol = matcher.group(1);
                String recDateStr = matcher.group(2);
                String direction = matcher.group(3);
                String completeUrl = matcher.group(4);

                //create recommendation object to populate required fields
                //  and insert it into the database
                System.out.println("Inserting to DB!");
                Recommendation rec = new Recommendation(stockSymbol, recDate, direction, completeUrl);
                rec.insertToDb(connection);
            }
        } catch (IOException e) {
            System.err.println("Unable to read "+RECS_FILE);
            e.printStackTrace();
        } finally {
            if(bufReader != null) {
                try{
                    bufReader.close();
                } catch (IOException e) {
                }
            }
        }

    }

.csv ファイルの読み取りにバッファー リーダーが使用されていることがわかります。バッファリングされたリーダーがタプルを優先キューに入れ、各プログラムスレッドが優先キューにアクセスするように、関数の外部で優先キューを設定する方法はありますか?

4

2 に答える 2

1

バッファリングされたリーダー、または実際には任意のリーダーまたはストリームは、その性質上、単一スレッドでのみ使用されます。優先キューは完全に独立した構造であり、実際の実装に応じて、複数のスレッドで使用できる場合と使用できない場合があります。つまり、短い答えは次のとおりです。いいえ、それらは 2 つの完全に無関係な概念です。

元の問題に対処するには、複数のスレッドでストリーミング ファイル アクセスを使用することはできません。理論的には使用できますが、行が固定幅ではないため、その時点までファイル内のすべてを読み取らずに行の先頭にRandomAccessFile到達することはできません。seek()さらに、データが固定レコードで構成されている場合でも、2 つの異なるスレッドでファイルを読み取るのは実際的ではない場合があります。

並列化できるのはデータベースの挿入だけですが、スレッドごとに個別のトランザクションを使用する必要があるため、トランザクション性が失われるという明らかな警告があります。(そうしない場合は、データベース操作を同期する必要があります。これは、何も獲得していないことを意味します。)

したがって、解決策は、1 つのスレッドから行を読み取り、文字列をExecutorService. これはスケーラビリティに優れていますが、ここでも注意点があります。データベース ロックのオーバーヘッドが増加すると、複数のスレッドを使用する利点が失われる可能性があります。

究極の教訓は、おそらく物事を過度に複雑にしないことです。単純な方法を試して、単純な方法がうまくいかない場合にのみ、より複雑な解決策を探すようにしてください。もう 1 つの教訓は、おそらく、マルチスレッドは I/O バウンドのプログラムには役立たないということです。

于 2012-03-24T21:45:06.630 に答える
0

@Biziclopの答えは(+1)にスポットがありますが、データベースの一括挿入について何かを追加すると思いました。

ご存じないかもしれませんが、ほとんどの SQL データベースでデータベースの自動コミットをオフにすると、一括挿入時に大きな効果が得られます。通常、各 SQL ステートメントの後、データベースはそれをディスク ストレージにコミットします。ディスク ストレージはインデックスを更新し、ディスク構造にすべての変更を加えます。この自動コミットをオフにすると、データベースcommitは最後に呼び出したときにのみこれらの変更を行う必要があります。通常、次のようなことを行います。

conn.setAutoCommit(false);
for (Recommendation rec : toBeInsertedList) {
    rec.insertToDb(connection);
}
conn.setAutoCommit(true);

さらに、自動コミットがデータベースでサポートされていない場合、多くの場合、トランザクションで挿入をラップすると同じことが達成されます。

役立つ可能性のある別の回答を次に示します。

于 2012-03-25T00:05:28.017 に答える