4

いくつかの情報をParallelでDataTableに追加しようとしていますが、ループが長すぎる場合、ループがフリーズするか、通常のforループよりも時間がかかる場合は、Parallel.Forループのコードです。

Parallel.For(1, linii.Length, index =>
                 {
                     DataRow drRow = dtResult.NewRow();
                     alResult = CSVParser(linii[index], txtDelimiter, txtQualifier);

                     for (int i = 0; i < alResult.Count; i++)
                     {
                         drRow[i] = alResult[i];
                     }
                     dtResult.Rows.Add(drRow);
                 }
             );

どうしたの?このParallel.Forループは通常のループよりもはるかに時間がかかりますが、何が問題になっていますか?

ありがとう!

4

2 に答える 2

5

DataTable2つの異なるスレッドからを変更することはできません。エラーになります。スレッドセーフになろうとはしませんDataTable。だから:そうしないでください。これは1つのスレッドから実行するだけです。ほとんどの場合、IOによって制限されているため、ストリームとして単一のスレッドで実行する必要があります。テキストデータを処理しているようです。あなたはおそらくfor行を持っているようですか?まあ、それはここでは非常に悪いです:string[]File.ReadAllLines()

  1. すべてを強制的にメモリにロードします
  2. すべてがメモリにロードされるのを待つ必要があります
  3. CSVは複数行形式です。1行==1行であるとは限りません。

コードプロジェクトのCsvReaderのようなものを使用する必要がありますが、一度に1行だけを使用する場合でも、StreamReaderを使用してください。

using(var file = File.OpenText(path)) {
    string line;
    while((line = file.ReadLine()) != null) {
        // process this line
        alResult = CSVParser(line, txtDelimiter, txtQualifier);

        for (int i = 0; i < alResult.Count; i++)
        {
            drRow[i] = alResult[i];
        }
        dtResult.Rows.Add(drRow);
    }
}

を使用するとこれは速くなりませんParallelので、私はそうしようとはしていません。ここでのボトルネックはIOです。ロックはオプションですが、大したことにはなりません。

alResult無関係ですが、ループ内で宣言されていないことに気付きました。つまり、元のコードalResultには、すべてのループ反復間で共有されるキャプチャされた変数が含まれています。つまり、各行はすでにひどく上書きされています。


編集:Parallelファイルから1,000,000行を読み取ることに関係がない理由の図:

アプローチ1:を使用ReadAllLinesしてラインをロードし、次にを使用してラインParallelを処理します。これには、物理​​ファイルIOの[固定時間]がかかり、並列化されます。CPUの作業は最小限で、基本的に[固定時間]を費やしました。ただし、多くのスレッドオーバーヘッドとメモリオーバーヘッドを追加し、すべてのファイルがロードされるまで開始することさえできませんでした。

アプローチ2:ストリーミングAPIを使用します。各行を1行ずつ読み取ります-各行を処理して追加します。ここでのコストは基本的に再びです:ファイルをロードするための実際のIO帯域幅の[固定時間]。だが; これで、スレッドのオーバーヘッド、同期の競合、割り当てる巨大なメモリがなくなり、すぐにテーブルの入力を開始します。

アプローチ3:本当に必要な場合、3番目のアプローチはリーダー/ライターキューで、1つの専用スレッド処理ファイルIOと行のエンキューを行い、2つ目はを実行しDataTableます。率直に言って、これははるかに可動部分であり、2番目のスレッドはその時間の95%をファイルからのデータの待機に費やします。アプローチ2に固執する!

于 2012-08-09T13:02:59.980 に答える
1
Parallel.For(1, linii.Length, index =>
{
  alResult = CSVParser(linii[index], txtDelimiter, txtQualifier);

  lock (dtResult)
  {
    DataRow drRow = dtResult.NewRow();
    for (int i = 0; i < alResult.Count; i++)
    {
       drRow[i] = alResult[i];
    }
    dtResult.Rows.Add(drRow);
  }
});
于 2012-08-09T13:01:04.187 に答える