【问题标题】:Server slowdown when copying files复制文件时服务器变慢
【发布时间】:2014-09-24 11:30:50
【问题描述】:

我有一个 C# 程序,它查询数据库 (server3) 以确定用户正在查找的文件,然后将这些文件从 (server1) 复制到 (server2)。

进一步简化

  • C# 应用程序在台式计算机上执行
  • 原始文件在 server1 上
  • 文件将被复制到 server2
  • Server3 包含数据库

当我在我的桌面上运行这个程序时,除了 server1 之外,一切都运行良好,它似乎在大约 5 分钟后几乎磨成一团糟,即使复制过程在 5 分钟后仍能正常运行。任何其他尝试连接到该服务器的应用程序/用户都不能。

他们只是得到一个旋转的光标,只有当我停止在我的桌面上运行程序时才会停止。在复制过程的前 5 分钟,对每个人来说一切都很好。超过 5 分钟范围时,文件会继续复制,但此时其他人开始遇到与 server1 的连接问题。

我什至尝试过使用sleep,因为我认为速度变慢是因为服务器 1 上的网络活动过多和/或磁盘 I/O 活动过多。 sleep 无济于事,同样的问题仍在继续。所以我猜这个问题是由于其他原因而发生的。

我正在使用与此类似的代码来复制文件

while (reader1.read(){
    // system.threading.thread.sleep(2000);
    system.io.file.copy(source, destination);
}

为什么会这样?

【问题讨论】:

  • 你是如何复制文件的?如果您只是在做一堆顺序文件副本,那么听起来您的服务器只是规格不足。如果您尝试并行运行多个副本,您可能应该将您的代码构造得不那么激进。
  • 我正在根据数据库查询复制特定文件。不是并行复制,是一次复制一个文件。
  • 这不能回答我的问题。你能显示一些代码吗?
  • 我使用的是代码system.io.file.copy(source, destination),它根据数据库查询结果循环运行。
  • 在常规的foreachfor 循环中,而不是并行循环?

标签: c# .net c#-4.0 .net-4.0


【解决方案1】:

根据this article, 的说法,减速的主要原因是文件复制使用了缓冲。

在 Windows Vista 或更高版本上,可以通过将 COPY_FILE_NO_BUFFERING 指定为 CopyFileEx() Windows API function 来避免使用缓冲。

您可以按如下方式指定 P/Invoke:

enum CopyProgressResult: uint
{
    PROGRESS_CONTINUE = 0,
    PROGRESS_CANCEL   = 1,
    PROGRESS_STOP     = 2,
    PROGRESS_QUIET    = 3
}

enum CopyProgressCallbackReason: uint
{
    CALLBACK_CHUNK_FINISHED = 0x00000000,
    CALLBACK_STREAM_SWITCH  = 0x00000001
}

delegate CopyProgressResult CopyProgressRoutine(
    long TotalFileSize,
    long TotalBytesTransferred,
    long StreamSize,
    long StreamBytesTransferred,
    uint dwStreamNumber,
    CopyProgressCallbackReason dwCallbackReason,
    IntPtr hSourceFile,
    IntPtr hDestinationFile,
    IntPtr lpData);

[Flags]
enum CopyFileFlags: uint
{
    COPY_FILE_FAIL_IF_EXISTS              = 0x00000001,
    COPY_FILE_RESTARTABLE                 = 0x00000002,
    COPY_FILE_OPEN_SOURCE_FOR_WRITE       = 0x00000004,
    COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008,
    COPY_FILE_COPY_SYMLINK                = 0x00000800, //NT 6.0+
    COPY_FILE_NO_BUFFERING                = 0x00001000
}

[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CopyFileEx
(
    string lpExistingFileName,
    string lpNewFileName,
    CopyProgressRoutine lpProgressRoutine, 
    IntPtr lpData,
    ref Int32 pbCancel,
    CopyFileFlags dwCopyFlags
);

然后这样调用(替换你自己的文件名);

int cancel = 0;
CopyFileEx(@"C:\tmp\test.bin", @"F:\test.bin", null, IntPtr.Zero, ref cancel, CopyFileFlags.COPY_FILE_NO_BUFFERING);

可能值得尝试一下,看看是否有帮助。

【讨论】:

  • @oshirowanen 它只想在前一行定义一个int cancel = 0;。 (我会更新示例)
  • 代码正在运行,但它仍然导致原始问题,即大约 5 分钟后,所有需要 server1 的应用程序/用户开始变慢,直到我停止从桌面运行复制应用程序。
  • @oshirowanen 嗯,值得一试。您是否阅读了我在回答开头引用的文章 - 它确实提出了其他一些建议。
猜你喜欢
  • 2021-05-10
  • 1970-01-01
  • 2013-08-23
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 1970-01-01
  • 1970-01-01
  • 2017-06-26
相关资源
最近更新 更多