如何在网络共享中使用C#实现高性能的filecopy方法?

时间:2010-07-06 10:58:38

标签: c# windows performance copy

我正在尝试实现一个filecopy方法,该方法可以与使用Windows资源管理器完成的副本的性能相匹配。

例如,从我们的nas到我的电脑的副本(使用Windows资源管理器),执行速度超过100mb /秒。

我当前的实现以大约55mb / sec的速度执行相同的复制,这已经比以29mb / sec执行的System.IO.File.Copy()更好。

static void Main(string[] args)
    {
        String src = @"";
        String dst = @"";

        Int32 buffersize = 1024 * 1024;
        FileStream input = new FileStream(src, FileMode.Open, FileAccess.Read, FileShare.None, 8, FileOptions.Asynchronous | FileOptions.SequentialScan);
        FileStream output = new FileStream(dst, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8, FileOptions.Asynchronous | FileOptions.SequentialScan);

        Int32 readsize = -1;
        Byte[] readbuffer = new Byte[buffersize];
        IAsyncResult asyncread;
        Byte[] writebuffer = new Byte[buffersize];
        IAsyncResult asyncwrite;

        DateTime Start = DateTime.Now;

        output.SetLength(input.Length);

        readsize = input.Read(readbuffer, 0, readbuffer.Length);
        readbuffer = Interlocked.Exchange(ref writebuffer, readbuffer);

        while (readsize > 0)
        {
            asyncwrite = output.BeginWrite(writebuffer, 0, readsize, null, null);
            asyncread = input.BeginRead(readbuffer, 0, readbuffer.Length, null, null);

            output.EndWrite(asyncwrite);
            readsize = input.EndRead(asyncread);
            readbuffer = Interlocked.Exchange(ref writebuffer, readbuffer);
        }

        DateTime Stop = DateTime.Now;

        TimeSpan Duration = Stop - Start;
        Double speed = input.Length / Duration.TotalSeconds; // bytes/s

        System.Console.WriteLine("MY Speed : " + (speed / 1024 / 1024).ToString() + " mo/sec");

        input.Close();
        output.Close();
        System.IO.File.Delete(dst);
    }

知道如何提高性能吗?

编辑:

该文件是从基于linux的nas读取的,带有一个10千兆以太网接口,后面有60个驱动器(不用担心它的性能,它运行得很好)并写入本地raid0,它可以写入数据大约140MB /秒。

瓶颈是目标的千兆网络接口,我无法使用当前代码访问该接口。

此外,删除写入不会使读取速度更快,因此我无法超过此55MB /秒的读取限制。

编辑2:

速度问题与源文件存储在网络共享中的事实有关。 只使用我的代码从本地驱动器读取,我的速度为112MB /秒。

编辑3:

Samba似乎不是问题。我在我的linux nas上用nfs共享替换了cifs share(samba),并且在我的win7客户端上使用samba的结果更糟。

使用nfs,我的复制方法和Windows资源管理器具有相同的性能,大约42MB /秒。

我没有想法......

编辑4:

为了确保Windows是问题所在,我安装了一个debian lenny,安装了我的nas nrough nfs,在单声道下使用相同的代码获得79MB /秒。

6 个答案:

答案 0 :(得分:5)

尝试将缓冲区大小更改为等于硬盘上的扇区大小 - 可能是4Kb。还可以使用System.Diagnostics.Stopwatch类进行计时。

我也不会在紧密循环中使用异步方法 - 它会导致一些开销消失并从池中分配一个线程来完成工作。

同样,请使用using语句来管理流的处理。但请注意,这会使您的计时时间偏差,因为您在停止计时器后正在处理对象。

答案 1 :(得分:4)

您是否尝试过较小的缓冲区大小?缓冲区大小为1mb非常大,通常缓冲区大小为4-64kb可以提供最佳性能。

此外,这可能与您的问题有关:How to write super-fast file-streaming code in C#?

也许您可以使用内存映射文件来提高性能:http://weblogs.asp.net/gunnarpeipman/archive/2009/06/21/net-framework-4-0-using-memory-mapped-files.aspx

答案 2 :(得分:1)

通常怀疑通过网络提高速度:

  • 拥有多个下载主题
  • 在文件将驻留的磁盘上预分配块

除此之外,您将受到硬件限制的支配。

答案 3 :(得分:1)

File.Copy()只是调用CopyFile() API,您可以尝试p / invoke SHFileOperation()这是shell使用的 - 它通常看起来更快。

答案 4 :(得分:1)

为了更深入地了解文件复制中涉及的设计选项和权衡,无论是否有网络共享,我建议您在几年前查看Mark Russinovich's blog post。除了硬盘扇区大小之外,还有更多的皱纹,例如......

  • SMB协议的数据包大小
  • 您愿意使用多少内存进行缓存(这可能会减慢其他进程的速度)
  • 是否可以牺牲速度的可靠性
  • 是否要增加感知速度或实际完成时间
  • 您希望在多个可能级别缓存的位置和数量
  • 您是否有兴趣提供可靠的反馈和时间估算

答案 5 :(得分:0)

可能唯一更快的选择是使用unbuffered IOReadFile FunctionCreateFile FunctionWriteFile FunctionFILE_FLAG_NO_BUFFERING标志位为2-6 MB缓冲区。

此外,您还必须将缓冲区大小与文件系统扇区大小等对齐

速度会快得多 - 尤其是在Windows XP中。

顺便说一句。我通过这种方式在条带化RAID 0阵列上实现了~400 MB带宽(使用4MB缓冲区)。