2

ネットワーク ドライブにある大きなファイル (~400 MB) の読み取りで興味深い問題が発生しています。最初は、完全なネットワーク アドレスを FileInfo に入力し、CopyTo 関数を使用してそれをローカルの一時ドライブに転送してから読み取りました。これは問題なく動作するようです。遅くはありませんが、速くはありません。CopyTo 関数は、プログラムのネットワーク使用率を常に 50% を超えて実行しているコンピューターを取得します。これはかなり良い結果です。

プロセスを高速化するために、ネットワーク ファイルをメモリ ストリームに直接読み込んで、いわば仲介者を排除しようとしました。これを (ここで説明した非同期コピー パターンを使用して) 試したところ、非常に遅くなりました。ネットワーク使用率が 2% を超えることはありません。まるで何かが私を抑制しているようです。参考までに、Windows エクスプローラー経由で同じファイルを直接コピーするときにネットワーク使用率を監視したところ、80 ~ 90% に達しました...ここで何が起こっているのかわかりません。以下は、私が使用した非同期コピー コードです。

string line;
List<string> results = new List<string>();

Parser parser = new Parser(QuerySettings.SelectedFilters, QuerySettings.SearchTerms,
QuerySettings.ExcludedTerms, QuerySettings.HighlightedTerms);

byte[] ActiveBuffer = new byte[60 * 1024];
byte[] BackBuffer = new byte[60 * 1024];
byte[] WriteBuffer = new byte[60 * 1024];

MemoryStream memStream = new MemoryStream();
FileStream fileStream = new FileStream(fullPath, FileMode.Open, FileSystemRights.Read, FileShare.None, 60 * 1024, FileOptions.SequentialScan);

int Readed = 0;
IAsyncResult ReadResult;
IAsyncResult WriteResult;

ReadResult = fileStream.BeginRead(ActiveBuffer, 0, ActiveBuffer.Length, null, null);
do
{
    Readed = fileStream.EndRead(ReadResult);

    WriteResult = memStream.BeginWrite(ActiveBuffer, 0, Readed, null, null);
    WriteBuffer = ActiveBuffer;

    if (Readed > 0)
    {
        ReadResult = fileStream.BeginRead(BackBuffer, 0, BackBuffer.Length, null, null);
        BackBuffer = Interlocked.Exchange(ref ActiveBuffer, BackBuffer);
    }

    memStream.EndWrite(WriteResult);
}
while (Readed > 0);

StreamReader streamReader = new StreamReader(memStream);
while ((line = streamReader.ReadLine()) != null)
{
    if (parser.ParseResults(line))
    results.Add(line);
}

fileStream.Flush();
fileStream.Close();

memStream.Flush();
memStream.Close();

return results;

更新 コメントに従って、私は次のことを試しました。私のネットワーク使用率は約 10 ~ 15% しかありませんでした...なぜそんなに低いのですか?

MemoryStream memStream = new MemoryStream();
FileStream fileStream = File.OpenRead(fullPath);

fileStream.CopyTo(memStream);

memStream.Seek(0, 0);
StreamReader streamReader = new StreamReader(memStream);

Parser parser = new Parser(QuerySettings.SelectedFilters, QuerySettings.SearchTerms,
QuerySettings.ExcludedTerms, QuerySettings.HighlightedTerms);

while ((line = streamReader.ReadLine()) != null)
{
if (parser.ParseResults(line))
results.Add(line);
}
4

3 に答える 3

4

私はパーティーに遅れましたが、最近、ネットワーク使用率が低いという同じ問題を抱えていました。多くの異なる実装を試した後、最終的に大きなバッファ (私の場合は 1MB) を持つ StreamReader がネットワーク使用率を 99 に増加させたことがわかりました。 %。他のオプションはどれも重要な変更を行いませんでした.

于 2014-08-20T20:03:05.127 に答える
1

ファイル全体をコピーしてから解析しても意味がありません。ネットワーク ドライブからファイルを開くだけで、.Net Framework がデータを配信するために最善を尽くします。あなたは MS の開発者よりも賢く、彼らよりも速くコピー メソッドを作成することができますが、それは本当に難しいことです。

于 2012-06-01T09:11:34.887 に答える
1

Reflector を使用すると、次の呼び出しが表示されます。

FileStream fileStream = File.OpenRead(fullPath);

サイズ 4096 バイト ( 0x1000 ) のバッファーを使用して終了します。

public FileStream(string path, FileMode mode, FileAccess access, FileShare share) : this(path, mode, access, share, 0x1000, FileOptions.None, Path.GetFileName(path), false)
{
}

FileStreamコンストラクターの 1 つを明示的に呼び出して、より大きなバッファー サイズとFileOption.SequentialScanを指定することができます。

これが役立つかどうかはわかりませんが、試すのは簡単です。

于 2012-06-01T20:14:58.217 に答える