27

100000 行の大きな txt ファイルがあります。n カウントのスレッドを開始し、このファイルからすべてのスレッドに固有の行を与える必要があります。

これを行う最善の方法は何ですか?ファイルを1行ずつ読み取る必要があり、イテレータをロックするにはグローバルにする必要があると思います。リストへのテキスト ファイルの読み込みには時間がかかり、OutofMemory例外が発生する可能性があります。何か案は?

4

6 に答える 6

23

61,277,203 行をメモリにロードし、値を Dictionary / ConcurrentDictionary() に押し込むための独自のベンチマークを実行した後、結果は、次のアプローチを使用することが最速であるという上記の @dtb の回答をサポートしているようです。

Parallel.ForEach(File.ReadLines(catalogPath), line =>
{

}); 

私のテストでは、次のことも示されました。

  1. File.ReadAllLines() と File.ReadAllLines().AsParallel() は、このサイズのファイルではほぼ同じ速度で実行されているように見えます。私の CPU アクティビティを見ると、どちらも私の 8 つのコアのうち 2 つを使用しているように見えますか?
  2. File.ReadAllLines() を使用して最初にすべてのデータを読み取ると、Parallel.ForEach() ループで File.ReadLines() を使用するよりもはるかに遅くなるようです。
  3. また、1 つのスレッドを使用してデータを読み取り、2 つ目のスレッドを使用してデータを処理する、プロデューサー/コンシューマーまたは MapReduce スタイルのパターンも試しました。これも、上記の単純なパターンよりも優れているようには見えませんでした。

このページには含まれていないため、参照用にこのパターンの例を含めました。

var inputLines = new BlockingCollection<string>();
ConcurrentDictionary<int, int> catalog = new ConcurrentDictionary<int, int>();

var readLines = Task.Factory.StartNew(() =>
{
    foreach (var line in File.ReadLines(catalogPath)) 
        inputLines.Add(line);

        inputLines.CompleteAdding(); 
});

var processLines = Task.Factory.StartNew(() =>
{
    Parallel.ForEach(inputLines.GetConsumingEnumerable(), line =>
    {
        string[] lineFields = line.Split('\t');
        int genomicId = int.Parse(lineFields[3]);
        int taxId = int.Parse(lineFields[0]);
        catalog.TryAdd(genomicId, taxId);   
    });
});

Task.WaitAll(readLines, processLines);

ここに私のベンチマークがあります:

ここに画像の説明を入力

特定の処理条件下では、生産者/消費者パターンが単純な Parallel.ForEach(File.ReadLines()) パターンよりも優れている可能性があると思います。ただし、この状況ではそうではありませんでした。

于 2014-10-10T05:44:06.330 に答える
5

何かのようなもの:

public class ParallelReadExample
{
    public static IEnumerable LineGenerator(StreamReader sr)
    {
        while ((line = sr.ReadLine()) != null)
        {
            yield return line;
        }
    }

    static void Main()
    {
        // Display powers of 2 up to the exponent 8:
        StreamReader sr = new StreamReader("yourfile.txt")

        Parallel.ForEach(LineGenerator(sr), currentLine =>
            {
                // Do your thing with currentLine here...
            } //close lambda expression
        );

        sr.Close();
    }
}

うまくいくと思います。(ここには C# コンパイラ/IDE はありません)

于 2013-06-19T10:14:47.343 に答える
3

上記の @dtb のように、ファイルを読み取り、ファイル内の個々の行を処理する最速の方法は次のとおりです。1) File.ReadAllLines() を配列に実行する 2) Parallel.For ループを使用して配列を反復処理する.

詳細なパフォーマンス ベンチマークについては、こちらを参照してください。

あなたが書かなければならないコードの基本的な要点は次のとおりです。

string[] AllLines = File.ReadAllLines(fileName);
Parallel.For(0, AllLines.Length, x =>
{
    DoStuff(AllLines[x]);
    //whatever you need to do
});

.Net4 でのより大きな配列サイズの導入により、十分なメモリがある限り、これは問題になりません。

于 2014-10-06T06:39:57.323 に答える