使用StreamWriter写入文件比通过慢速网络的文件复制慢得多

Ste*_*olt 4 c# performance networking streamwriter

我有一个程序试图将相当大量的文本写入海外远程服务器上的文件,该文件的网络连接速度很慢.

使用下面的代码,其中outputFileContentStringBuilder:

using (var outfile = new StreamWriter(myRemoteFilePath))
{
    outfile.Write(outputFileContent.ToString());
}
Run Code Online (Sandbox Code Playgroud)

它需要花费很长时间才能运行(几分钟),而如果我先写入本地文件然后将其复制到远程位置,则会更快(20-30秒):

string tempFilePath = Path.GetTempFileName();
using (var outfile = new StreamWriter(tempFilePath))
{
    outfile.Write(outputFileContent.ToString());
}

System.IO.File.Copy(tempFilePath, myRemoteFilePath, true)
Run Code Online (Sandbox Code Playgroud)

知道为什么会这样吗?我唯一的猜测是它与网络缓冲有关,或者可能是因为流编写器不知道它需要提前多大.

Rog*_*erN 10

如果使用默认缓冲区大小创建StreamWriter,则底层SMB协议将以不大于4096字节的块发出写请求,这意味着通过网络进行大量往返.您可以将StreamWriter的缓冲区大小增加到最大64k,以减少往返次数:

using (var outfile = new StreamWriter(myRemoteFilePath, false, Encoding.ASCII, 0x10000))
Run Code Online (Sandbox Code Playgroud)

将缓冲区大小增加到64k以上在任何情况下都无济于事,因为底层SMB协议不支持超过64k的缓冲区长度.请注意,直接文件复制仍然使用SMB协议,因此从网络流量角度来看,除了缓冲区大小之外,操作之间几乎没有差别.

  • MTU对总传输时间的影响不会像SMB协议的缓冲区长度那么大,因为通过MTU的分组分段不会导致SMB ACK形式的额外往返通信.我认为这个答案*解释了与标准文件副本相比的差异,实际上在我自己的测试中,如果我只是增加StreamWriter的缓冲区大小,那么性能与标准文件复制操作相同. (2认同)