【问题标题】:File read over network very slow通过网络读取文件非常慢
【发布时间】:2012-06-05 21:58:56
【问题描述】:

我在读取网络驱动器上的大文件 (~400 mb) 时遇到了一个有趣的问题。最初,我将完整的网络地址输入 FileInfo 并使用 CopyTo 函数将其传输到本地临时驱动器,然后读取它。这似乎工作正常,它不慢但不快 - 只是嗯。 CopyTo 功能可以让运行该程序的计算机的网络利用率始终保持在 50% 以上,相当不错。

为了加快进程,我尝试将网络文件直接读取到内存流中,可以说是省去了中间人。当我尝试这个(使用here 描述的异步复制模式)时,速度非常慢。我的网络利用率甚至从未超过 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;

更新 根据 cmets,我刚刚尝试了以下方法。我的网络利用率只有 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);
}

【问题讨论】:

  • 鉴于写入MemoryStream 确实非常快,如果您尝试同步读取会发生什么?
  • 当您在打回来。这就是同步的定义。
  • @JonSkeet 好的,我按照您的建议尝试了一些不同的方法(我认为)。如果有机会,请阅读原始帖子的更新
  • 没有看到将其全部读入内存并然后解析它的意义。这只是浪费时间和空间。直接从网络提供解析器。

标签: c# .net winforms file-io network-programming


【解决方案1】:

我迟到了,但最近也遇到了同样的网络利用率低的问题,在尝试了很多不同的实现之后,如果最后发现带有大缓冲区(在我的情况下为 1MB)的 StreamReader 增加了网络利用率达到 99%。 其他选项都没有做出重大改变。

【讨论】:

  • 那是很久以前的事了,但我想我做了 3 件事来解决这个问题,其中之一是增加缓冲区大小。谢谢!
【解决方案2】:

复制整个文件然后解析它是没有意义的。只需从网络驱动器打开文件,让 .Net Framework 尽最大努力为您提供数据。你可以比 MS 开发人员更聪明,你可以比他们更快地创建一个复制方法,但这确实是一个挑战。

【讨论】:

  • 问题是当我在网络驱动器上打开它并直接读取它时,我只能获得大约40%的网络利用率。复制到本地驱动器可以获得大约 95% 的网络利用率,因此速度要快得多......我一生都无法弄清楚为什么直接读取只有 30-40%,如果它像复制一样获得 90%,我会设置
  • 这似乎是最好的解决方案,虽然我希望我知道为什么网络利用率会有如此巨大的差异。
【解决方案3】:

使用 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 构造函数之一,并指定更大的缓冲区大小和 FileOption.SequentialScan

不确定这会有所帮助,但很容易尝试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-03
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多