C#(.NET 4.5)を使用するファイルのセットを複数の場所にコピーしたいとします(たとえば、フォルダの内容をコンピュータに接続された2台のUSBドライブにコピーします)。
foreachループとFile.Copy
を使用するより効率的な方法がありますか?複数のファイルを複数の場所にコピーする
(可能な)解決策に向けて作業してください。
私の最初の考えは、マルチスレッドアプローチのようなものでした。いくつかの読書と研究の後、何らかの並列処理や非同期処理を盲目的に設定することは、IOに関しては(Why is Parallel.ForEach much faster then AsParallel().ForAll() even though MSDN suggests otherwise?のように)良い考えではないことがわかりました。
ボトルネックは、特に従来のドライブの場合は、同期して読み書きできるため、ディスクです。それは私に考えさせました。もしそれを一度読んだら複数の場所に出力すればどうなりますか?結局のところ、私のUSBドライブのシナリオでは、私は複数の(出力)ディスクを扱っています。
どうすればいいのか分かりません。私が見たアイディア(Copy same file from multiple threads to multiple destinations)は、各ファイルのすべてのバイトをメモリに読み込んだ後、宛先をループして次のファイルに移動する前に各位置にバイトを書き出すことでした。ファイルが大きければ、それは悪い考えです。私がコピーするファイルの一部はビデオで、1 GB(またはそれ以上)になる可能性があります。 1GBのファイルを別のディスクにコピーするだけでメモリにロードすることをお勧めします。
大容量ファイルに柔軟性を持たせるために、私が得た最も近いものは以下の通りです(How to copy one file to many locations simultaneouslyに基づいています)。このコードの問題は、私はまだ単一の読み取りと複数の書き込みが起こっていないということです。現在、マルチリードとマルチライトです。このコードをさらに最適化する方法はありますか?チャンクをメモリに読み込み、次のチャンクに移動する前にそのチャンクを各デスティネーションに書き込むことができますか(上記のアイデアと同じですが、全体の代わりにチャンクされたファイル)?あなたは、読み取り/書き込み操作のためのいくつかのasync/await
構造を導入しようとすることができるので、一般的には
files.ForEach(fileDetail =>
Parallel.ForEach(fileDetail.DestinationPaths, new ParallelOptions(),
destinationPath =>
{
using (var source = new FileStream(fileDetail.SourcePath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var destination = new FileStream(destinationPath, FileMode.Create))
{
var buffer = new byte[1024];
int read;
while ((read = source.Read(buffer, 0, buffer.Length)) > 0)
{
destination.Write(buffer, 0, read);
}
}
}));
あなたの助けてくれてありがとう@VMAtm - 私は先週私のコードを調整していて、並列非同期書き込み( 'Task.WaitAll'を使って)で一度読み込みを管理しました。私はまだ別の(.NET)プログラムで見たスピードには達していないようですが、アプリケーションディレクトリの_USBLib.dll_に気づいたので、コピー用に別のものを使用しているのだろうかと思います。 IOバッファについて多くのことを知っていますか?バッファを何か大きいもの(通常の81920バイトの代わりに60MBのようなもの)にプッシュすると気づいたことがありますが、それは速いですが、大きなバッファは良いアイデアですか? – Pete
偶然にも、私は今日のバッファサイズの調査を行いました。私が言う限りでは、より大きなバッファのパフォーマンスを測定する必要があります。何人かは、「81920」は256KB 。それはあなた次第です。ただそれを測定してください。もし失敗すれば60 MBの危険性があります。おそらくそのデータはすべて失われます。 – VMAtm
さて、バッファサイズでいくつかのテストをする必要があるようです。あなたのヒントとポインタをありがとう。私は実際にあなたが応答を投稿するのに気をつけて、あなたが有用な洞察とリンクを与えたので、あなたに答えを与えるでしょう(私は数日前にそれを行う方法を考え出しました)。 – Pete