2016-10-01 20 views
0

私はかなり一般的な問題だと考えているが、自分自身で、またはこのフォーラムを閲覧することで良い解決策を見つけることができなかった。私はなどCで効率的にファイルを書き込む大ファイルリストを作成する

ファイル名、ファイルパス、ファイルサイズ、ハッシュ、最大の問題など、いくつかの追加情報を含むフォルダのファイルリストを取得するためのツールを書かれている

問題私が持っているのは、フォルダの中に何百万ものファイルが入っているということです。

可能な解決策

私は2つのソリューションを持っているが、それらのどちらも理想的です。

  1. ファイルが読み取られるたびに、情報はファイルにまっすぐ書き込まれます。これは問題ありませんが、ファイルをロックしているスレッドの問題に遭遇せずにファイルをマルチスレッドすることはできません。

  2. ファイルが読み取られるたびに、その情報は、ConcurrentBagなどの何らかの形式のコレクションに追加されます。私は、ファイルの列挙をマルチスレッド化し、それらをコレクションに追加することができます。列挙が完了したら、File.WriteAllLinesを使用してコレクション全体をファイルに書き込むことができます。コレクションに5千万エントリを追加すると、ほとんどのマシンのメモリが不足します。

その他のオプション

コレクションに項目を追加し、それはそのようなコレクションか何かで、レコードの一定数に到達したときにファイルに書き込む方法はありますか?

私はBlockingCollectionを調べましたが、プロデューサがマルチスレッド化されるため、実際にはすぐにいっぱいになりますが、コンシューマはシングルスレッドのみになります。

+1

あなたのオプション2に行くことができますが、いくつかの事前定義されたしきい値より大きいエントリー、すなわちファイルに書き込んで、あなたの並行バッグを定期的に清掃してください。 – serhiyb

+3

サイドノート:ディスク(および他のすべてのI/O操作)は、一般的にはCPUバインディングではなくI/Oバインドです。マルチスレッドのような操作を単一のソースに対して実行しても、パフォーマンスが向上する必要はありません。人々が主な理由は、そのようなコードを書くことは、シングルスレッド操作よりも面白いことです - あなたがそれをやっている理由があなたの目標に沿っていることを知っていることを確認します。 –

+0

@AlexeiLevenkov、ありがとう。このアプリケーションはストレージサーバーで使用するため、IOは単一のマシンのディスク上で実行するのと同じ問題であってはなりません。 – Ninja

答えて

1

すべてのスレッドで共有されるFileStreamを作成します。そのFileStreamに書き込む前に、スレッドはそれをロックする必要があります。 FileStreamにはいくつかのバッファがあります(4096バイトの場合は覚えています)。実際には毎回ディスクに書き込まれません。 4096バイトで十分でない場合は、そのまわりのBufferedStreamを使用することができます。

1

BlockingCollectionが必要なものです。大きなバッファを使用して1つを作成し、1つのライタースレッドが実行中に開いたままのファイルに書き込むようにすることができます。

読み取りが時間的に支配的な操作である場合、キューは空に近くなり、全体の時間は読み取り時間よりわずかに長くなります。

書き込みが時間的に支配的な操作である場合、(メモリ不足の状態を防ぐために)設定した制限に達するまで待ち行列がいっぱいになり、プロデューサはライターの進歩によってのみ前進します。合計時間は、すべてのレコードを1つのファイルに順番に書き込むのに必要な時間になります(ライターが最も遅い部分である場合)。

複数のブロッキングコレクションをパイプライン処理することで、パフォーマンスを少し向上させることができます。ハッシュ計算(CPUバウンド操作)を読み取りまたは書き込み操作から分離する可能性があります。TPL DataFlowライブラリを考えてみてください。

関連する問題