问题 限制File.Copy的速度


我们在C#中使用一个简单的File.Copy将数据库备份移动到额外的位置。

但是在某些服务器上,这会导致SQL服务器停止工作。这些服务器的内存非常有限,因此它们经常将数据分页到硬盘驱动器。

虽然我们 应该 买更多的记忆,这不会发生很长一段时间: - /

所以我想知道我是否可以某种方式限制File.Copy操作的速度? (从而为SQL服务器提供了访问硬盘的空间)

我可以使用两个流的“旧学校”方法,通过缓冲区读取和写入,并且在读取之间只睡5毫秒左右。但我真的更喜欢更整洁的解决方案,如果有这样的话。


11829
2017-07-02 11:35


起源

你想限制速度,或者实际上是内存占用? - Frank
您是否尝试在线程上运行复制代码 minimal priority?不确定它会有用,因为它使用kernel32 CopyFile 功能。 - Jaroslav Jandek
只是不要将备份与SQL Server用于其dbase的驱动器相同。 - Hans Passant
汉斯:我会检查使用哪些驱动器,但它也可能是控制器容量 - 我不确定它们在有问题的服务器上的速度有多快。弗兰克:我不认为File.Copy分配了大量内存,所以它主要是我想限制的速度。 - Steffen
C#没有File.Copy方法。你指的是.NET File.Copy方法吗? - John Saunders


答案:


CopyFileEx 可能会做你需要的 - 它有一个你可以用作人工的回调函数 slowing method (虽然没有尝试过这种情况,所以我不确定真正的效果 - 值得一试恕我直言)。


7
2017-07-02 12:00



我可以试一试 - 我会看看MSDN是否有关于回调的更多信息(它被称为等等的频率) - Steffen
它应该比使用C#流更快。缓冲区是 65536B 在WXP上(复制块时发生通知)。在Vista和W7上它更大。您也可以将文件仅复制到1台计算机,然后将文件从那里复制到其他备份位置。 - Jaroslav Jandek
听起来不错,我对流的主要关注实际上是与原生API函数相比的性能(File.Copy也是如此:CopyFile)我会在周二检查它,因为我无法开始工作它更快。 - Steffen
刚刚实现了CopyFileEx - 并且在回调中睡觉(甚至是如此简短)正是我想要的。它为服务器提供了一些其他功能。所以感谢您的好建议:-) - Steffen


您是否尝试过将复制过程优先于正常值?您可以通过任务管理器或使用 start 命令:

> start myCopyApp.exe /BELOWNORMAL

2
2017-07-02 11:39



如果系统受CPU约束,那将会有效,但如果它受I / O约束,则可能不行? - ChrisW
由于OP声明'这些服务器的内存非常有限',我认为它既不是这些,也不是内存限制。 - Frank
@Frank我认为内存限制导致磁盘访问(到交换文件),因此相当于受I / O限制。 - ChrisW
ChrisW我也相信它的I / O界限 - 就像我说他们与数据库的大小相比内存很少,因此它们分页很多,这确实会导致磁盘访问。我怀疑低优先级会有多大帮助,因为CPU在复制时有足够的余量。谢谢你的想法:-) - Steffen


一个不能通过File.Copy获得。您还有许多其他选择。正如你所说,你可以手动流式传输字节,偶尔也会睡觉。你可以使用BITS的实现,虽然这有点OTT。

此外,如果问题是内存 - 压缩文件或将其分块为较小的文件以便稍后重建。


2
2017-07-02 12:10



注意:对于SQL Server 2008+,您可以在“备份数据库”页面中启用备份压缩。 - Jaroslav Jandek
压缩的好电话,但这些仍然坚持SQL Server 2005 :-( - Steffen


我可以使用两个流的“旧学校”方法,通过缓冲区读取和写入,并且在读取之间只睡5毫秒左右。

如果这样做,请查看使用FILE_FLAG_NO_BUFFERING标志:否则无论应用程序缓冲区有多小,文件系统都将进行缓冲(因此会导致额外的交换)。


1
2017-07-04 08:37



由于缓冲存储器将使用很多,Windows 应该 不交换那部分内存(+它的内存占用非常小),而是交换其他(较少使用的)内存部分。此外,CPU和磁盘IO操作将显着增加。 - Jaroslav Jandek
@Jaroslav Jandek - 输入和输出文件上的FILE_FLAG_NO_BUFFERING将影响/禁用缓冲(例如预读缓冲),否则缓冲将在文件系统驱动程序内/由文件系统驱动程序隐式执行。我建议应该禁用此缓冲,因为启用此文件系统缓冲(默认情况下)会占用内存并因此导致交换,他甚至不需要它(因为文件副本只想触摸每个一部分文件)。 - ChrisW
@ChrisW:你需要在某处读取数据(到缓冲区),然后写入一个文件(可以是无缓冲的 - 直接写入)。如果操作不是顺序操作,则会浪费缓冲区。在这种情况下,无论如何都需要它。对于复制,这种方法是无用的,因为系统已经有效地执行了该操作(如果您手动执行ReadFile和WriteFile,则会有所不同)。此外,它还需要大量的WINAPI处理和正确的缓冲区大小和对齐,以及文件系统的许多部分...... - Jaroslav Jandek
@ChrisW:如果问题是 我想尽快复制一个大文件,我会同意你的看法。但是,由于顺序无缓冲IO的优势仅在大缓冲区大小(1MB +)时才真正显着,因此它将使用比缓冲IO更多的内存(也就是每个缓冲区的CPU和磁盘IO(非每个字节)。)。 - Jaroslav Jandek
@ChrisW:我明白了。分配了大约128kB的额外内存对我来说看起来不是很多开销(即使是几个MB也不应该成为问题恕我直言)。如果他们的服务器是486,内存24MB,我会发现这是一个问题...我只是说你的建议是过度优化的情况。运用 FileStream 同 FileOptions.SequentialScan 将花费你只有~128kB的内存(不会交换)和每字节大约2个CPU周期,这在这种情况下是微不足道的(恕我直言)。 - Jaroslav Jandek