复制文件时服务器变慢

3
我有一个C#程序,该程序查询数据库(server3)以确定用户需要的文件,然后从(server1)复制这些文件到(server2)。
进一步简化:
- C#应用程序在桌面计算机上执行 - 原始文件位于server1上 - 文件需要复制到server2 - server3包含数据库
当我在桌面上运行此程序时,除了server1外,一切正常。大约5分钟后,即使在5分钟后拷贝过程仍在继续,server1似乎也几乎停滞不前。任何尝试连接到该服务器的其他应用程序/用户都无法连接。他们只会看到一个旋转的光标,只有在我停止在桌面上运行该程序时才会停止。对于拷贝过程的前5分钟,所有人都没问题。超过5分钟后,文件仍在继续复制,但其他人开始遇到与server1的连接问题。
我甚至尝试使用 `sleep` ,因为我假设减慢速度是由于server1上的网络活动和/或磁盘I / O活动过多造成的。然而, `sleep` 对解决问题没有帮助,同样的问题继续出现。所以我猜测问题是由于其他原因引起的。
我正在使用类似于以下内容来复制文件的代码:
while (reader1.read(){
    // system.threading.thread.sleep(2000);
    system.io.file.copy(source, destination);
}

为什么会发生这种情况?

你是如何复制文件的?如果你只是在进行一堆顺序文件复制,那么你的服务器可能配置不足。如果你想要并行运行多个副本,你应该考虑调整代码结构,使其更加温和。 - Dan Puzey
我正在根据数据库查询复制特定的文件。不是并行复制,而是一次复制一个文件。 - oshirowanen
那并没有回答我的问题。你能展示一些代码吗? - Dan Puzey
我正在使用代码 system.io.file.copy(source, destination),它基于数据库查询结果运行循环。 - oshirowanen
在常规的foreachfor循环中,而不是并行循环? - Dan Puzey
是的,可以使用常规的 while(reader1.read()) 作为循环。 - oshirowanen
1个回答

2
根据这篇文章,文件复制的主要原因是使用了缓冲区。
在Windows Vista或更高版本中,可以通过将COPY_FILE_NO_BUFFERING指定给CopyFileEx() Windows API函数来避免使用缓冲区。
您可以按照以下方式指定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; 即可。(我会更新示例) - Matthew Watson
代码可以运行,但仍然导致原来的问题,即大约5分钟后所有需要使用server1的应用程序/用户开始变慢,直到我停止从桌面运行复制应用程序。 - oshirowanen
@oshirowanen 哦,好吧,值得一试。你读了我回答开头引用的那篇文章吗?它确实提出了一些其他的建议。 - Matthew Watson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接