如何从网络共享在C#中实现performant filecopy方法?

如何从网络共享在C#中实现performant filecopy方法?,c#,windows,performance,copy,C#,Windows,Performance,Copy,我正在尝试实现一个filecopy方法,该方法可以与windows资源管理器的复制性能相匹配 例如,从nas到我的计算机的拷贝(使用windows资源管理器),执行速度超过100mb/秒 我当前的实现以大约55mb/秒的速度执行相同的复制,这已经比以29mb/秒的速度执行的System.IO.File.copy()要好 static void Main(string[] args) { String src = @""; String dst = @"";

我正在尝试实现一个filecopy方法,该方法可以与windows资源管理器的复制性能相匹配

例如,从nas到我的计算机的拷贝(使用windows资源管理器),执行速度超过100mb/秒

我当前的实现以大约55mb/秒的速度执行相同的复制,这已经比以29mb/秒的速度执行的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中读取,该nas具有10千兆以太网接口,后面有一个60驱动器的san(不用担心它的性能,它工作得很好),然后写入本地raid0,该raid0可以以大约140MB/秒的速度写入数据

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

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

编辑2:

速度问题与源文件存储在网络共享上这一事实有关。 只有使用我的代码从本地驱动器读取数据,我才能获得112MB/秒的速度

编辑3:

桑巴舞似乎不是问题。我在linux nas上将cifs共享(samba)替换为nfs共享,结果比在win7客户机上使用samba更糟

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

我没有主意了

编辑4:


为了确保windows是问题所在,我安装了debian lenny,通过nfs安装了nas,在mono下使用相同的代码获得了79MB/秒。

尝试更改缓冲区大小,使其与硬盘上的扇区大小相等-可能是4Kb。也可使用System.Diagnostics.Stopwatch类进行计时

我也不会在一个紧密的循环中使用异步方法——这会带来一些开销,并从池中分配一个线程来完成这项工作


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

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

  • 有多个下载线程
  • 在文件将驻留的磁盘上预分配块
除此之外,您还受制于硬件限制。

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

此外,这可能与您的问题有关:


也许您可以使用内存映射文件来提高性能:

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

要更深入地了解设计选项以及文件复制中涉及的权衡,无论是否使用网络共享,我建议您看看几年前的情况。除了硬盘扇区大小之外,还涉及到很多皱纹,例如

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

唯一更快的选择可能是使用
无缓冲IO
:,带有
文件标志\u无缓冲
标志和2-6MB缓冲

同样,通过这种方式,您必须将缓冲区大小与文件系统扇区大小等对齐

这将大大加快速度,尤其是在Windows XP中


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

扇区大小的小倍数也可以正常工作。。。测试从1x到16x的任何数据都可能会在其中一个数据流中显示出显著的增益。仅同步执行一次读取并不能提供更好的性能。我不确定同时从流中读取数据和异步写入另一个流是否会更快-您将同时使用两个任务来处理I/O。对于较小的文件,您是否尝试过将这些文件读入RAM,然后再写入?此外,您可以写入更大的数据块或一次写入所有数据块,因此不严格要求缓冲。只有当瓶颈不是I/O时,多个下载线程才能工作,这很可能是。@Adam-可能是网络,在这种情况下,它可以稍微提高性能。不过,与任何性能相关的技术一样,它都是关于测试和测量各种技术的。无缓冲I/O如何帮助NAS存储?当然,网络和硬盘访问成本将占主导地位。当存在多个瓶颈时,消除缓冲很可能会降低性能。我没有注意到NAS部分。您只能通过系统删除自动缓冲。您仍然可以缓冲数据,但可以选择缓冲区大小。对于速度较慢的磁盘来说,这无关紧要,但对于速度较快的raid阵列和Tb网络来说,无缓冲IO性能非常显著——更不用说它在CPU上很容易实现。如果我不必使用它,我就不会使用它,因为WinAPI处理太多了。无论如何,您可以在NAS中使用无缓冲IO。在最终进入rabbit整体(重叠+无缓冲IO)之后,我可以确认这是实现真正性能的唯一方法。从横向扩展NAS读取时,通过双10g链路获得2,25 GiB/秒(感谢SMB3)。Windows资源管理器也可能正在利用文件系统缓存,并显示100 mb/秒的传输,但内核可能尚未将整个文件写入磁盘,操作完成后在后台执行此操作。怎么发