0

次のコードがあります。同じタスクを達成するためのより効率的な方法はありますか?

  1. フォルダーを指定して、フォルダー内のファイルをループします。
  2. 各ファイル内で、最初の 4 つのヘッダー行をスキップし、
  3. スペースに基づいて行を分割した後、結果の配列に含まれる要素が 7 つ未満の場合はスキップし、
  4. 指定された要素が辞書に既に存在するかどうかを確認します。そうであれば、カウントを増やします。そうでない場合は、追加します。

複雑なプロセスではありません。これを行うより良い方法はありますか?リンク?

string sourceDirectory = @"d:\TESTDATA\";

string[] files = Directory.GetFiles(sourceDirectory, "*.log", 
    SearchOption.TopDirectoryOnly);

var dictionary = new Dictionary<string, int>();

foreach (var file in files)
{
    string[] lines = System.IO.File.ReadLines(file).Skip(4).ToArray();

    foreach (var line in lines)
    {
        var elements = line.Split(' ');

        if (elements.Length > 6)
        {
            if (dictionary.ContainsKey(elements[9]))
            {
                dictionary[elements[9]]++;
            }
            else
            {
                dictionary.Add(elements[9], 1);
            } 
        }
    }
}
4

4 に答える 4

1

Linqy があなたにすべきこと。より効率的であることを疑います。そして、ほとんどの場合、デバッグが面倒です。しかし、最近は非常にトレンディです。

static Dictionary<string,int> Slurp( string rootDirectory )
{
  Dictionary<string,int> instance = Directory.EnumerateFiles(rootDirectory,"*.log",SearchOption.TopDirectoryOnly)
                                             .SelectMany( fn => File.ReadAllLines(fn)
                                                                    .Skip(4)
                                                                    .Select( txt => txt.Split( " ".ToCharArray() , StringSplitOptions.RemoveEmptyEntries) )
                                                                    .Where(x => x.Length > 9 )
                                                                    .Select( x => x[9])
                                                        )
                                             .GroupBy( x => x )
                                             .ToDictionary( x => x.Key , x => x.Count()) 
                                             ;
  return instance ;
}
于 2013-04-26T18:50:53.663 に答える
0

ファイルの読み取りは、操作の中で最も消費量の多い部分になると思います。多くの場合、異なるスレッドで一度に複数のファイルを読み込もうとすると、パフォーマンスが向上するどころか悪化しますが、ドライブをできるだけビジー状態に保つことができるように、ファイルを読み取るだけのスレッドを用意すると役立つ場合があります。

ファイルが大きくなる可能性があり (おそらく)、32K バイト (8,000-32,000 Unicode 文字) を超える行がない場合は、約 32K または 64K バイト (文字ではない) のチャンクでファイルを読み取ることをお勧めします。ファイルをバイトとして読み取り、自分で行に分割する方が、行として読み取るよりも高速な場合があります。これは、分割が物理ディスク アクセスとは別のスレッドで発生する可能性があるためです。

ディスク アクセス用の 1 つのスレッドと、解析とカウント用の 1 つのスレッドから始めて、その間にブロッキング キューを配置することをお勧めします。ディスク アクセス スレッドは、32K のバイト配列、有効なバイト数の表示 [ファイルの最後で 32K 未満の場合がある]、およびそれが最後かどうかのインジケータを含むデータ項目をキューに入れる必要があります。ファイルの記録。解析スレッドは、これらの項目を読み取り、それらを行に解析して、適切なカウントを更新する必要があります。

計数のパフォーマンスを改善するには、次のように定義すると役立つ場合があります。

class ExposedFieldHolder<T> {public T Value; }

を持っていDictionary<string, ExposedFieldHolder<int>>ます。ExposedFieldHolder<int>辞書スロットごとに新しいものを作成する必要がありますが、後者のステートメントが として変換され、読み取り時に要素を一度検索し、書き込み時に再度要素を検索する必要があるため、dictionary[elements[9]].Value++;より高速になる可能性があります]。dictionary[elements[9]]++;dictionary[elements[9]] = dictionary[elements[9]]+1;

複数のスレッドで解析とカウントを行う必要がある場合は、各スレッドに独自のキューがあり、ディスク読み取りスレッドが各ファイルの後にキューを切り替えることをお勧めします [ファイルのすべてのブロックは同じスレッドで処理する必要があるため、テキスト行は 2 つのブロックにまたがる場合があります]。さらに、 を使用することもできますConcurrentDictionaryが、各スレッドに独自の独立したスレッドを持たせDictionary、最後に結果を統合する方が効率的かもしれません。

于 2013-04-26T19:07:52.787 に答える
0

より良いパフォーマンスまたはより洗練されたコードを探しているかどうかはわかりません。機能的なスタイルの linq を好む場合は、次のようになります。

var query= from element in
                       (
                           //go through all file names
                           from fileName in files
                           //read all lines from every file and skip first 4
                           from line in File.ReadAllLines(fileName).Skip(4)
                           //split every line into words
                           let lineData = line.Split(new[] {' '})
                           //select only lines with more than 6 words
                           where lineData.Count() > 6
                           //take 6th element from line
                           select lineData.ElementAt(6)
                       )
                   //outer query will group by element
                   group element by element
                   into g
                   select new
                       {
                           Key = g.Key,
                           Count = g.Count()
                       };
  var dictionary =  list.ToDictionary(e=>e.Key,e=>e.Count);

結果は、単語をキーとし、単語の出現回数を値とする辞書です。

于 2013-04-26T18:39:21.017 に答える