jak*_*don 33 c# windows performance
我的问题在于文件复制性能.我们有一个媒体管理系统,需要在文件系统上大量移动文件到不同的位置,包括同一网络上的Windows共享,FTP站点,AmazonS3等.当我们都在一个Windows网络上时,我们可以使用System.IO.File.Copy(源,目标)复制文件.由于我们所拥有的很多次都是输入流(如MemoryStream),我们尝试抽象复制操作以获取输入流和输出流,但我们看到了大量的性能下降.下面是一些用于复制文件以用作讨论点的代码.
public void Copy(System.IO.Stream inStream, string outputFilePath)
{
int bufferSize = 1024 * 64;
using (FileStream fileStream = new FileStream(outputFilePath, FileMode.OpenOrCreate, FileAccess.Write))
{
int bytesRead = -1;
byte[] bytes = new byte[bufferSize];
while ((bytesRead = inStream.Read(bytes, 0, bufferSize)) > 0)
{
fileStream.Write(bytes, 0, bytesRead);
fileStream.Flush();
}
}
}
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么这比File.Copy执行速度慢得多?我能做些什么来提高性能吗?我是否只需要使用特殊逻辑来查看我是否从一个窗口位置复制到另一个窗口位置 - 在这种情况下我将只使用File.Copy而在其他情况下我将使用流?
请告诉我您的想法以及是否需要其他信息.我尝试了不同的缓冲区大小,似乎64k缓冲区大小对于我们的"小"文件来说是最佳的,256k +对于我们的"大"文件来说是一个更好的缓冲区大小 - 但无论哪种情况下它都比File.Copy执行得更糟糕( ).提前致谢!
arb*_*ter 23
File.Copy是围绕CopyFile Win32功能构建的,这个功能需要MS工作人员的大量关注(请记住这个与Vista相关的慢速复制性能线程).
提高方法性能的几条线索:
异步复制模式的示例:
int Readed = 0;
IAsyncResult ReadResult;
IAsyncResult WriteResult;
ReadResult = sourceStream.BeginRead(ActiveBuffer, 0, ActiveBuffer.Length, null, null);
do
{
Readed = sourceStream.EndRead(ReadResult);
WriteResult = destStream.BeginWrite(ActiveBuffer, 0, Readed, null, null);
WriteBuffer = ActiveBuffer;
if (Readed > 0)
{
ReadResult = sourceStream.BeginRead(BackBuffer, 0, BackBuffer.Length, null, null);
BackBuffer = Interlocked.Exchange(ref ActiveBuffer, BackBuffer);
}
destStream.EndWrite(WriteResult);
}
while (Readed > 0);
Run Code Online (Sandbox Code Playgroud)
除了反射器,我们可以看到File.Copy实际上调用了Win32 API:
if (!Win32Native.CopyFile(fullPathInternal, dst, !overwrite))
Run Code Online (Sandbox Code Playgroud)
哪个解决了
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool CopyFile(string src, string dst, bool failIfExists);
Run Code Online (Sandbox Code Playgroud)
三个变化将显着提高性能:
在我尝试的实验中,这似乎快了 3-4 倍:
public static void Copy(System.IO.Stream inStream, string outputFilePath)
{
int bufferSize = 1024 * 1024;
using (FileStream fileStream = new FileStream(outputFilePath, FileMode.OpenOrCreate, FileAccess.Write))
{
fileStream.SetLength(inStream.Length);
int bytesRead = -1;
byte[] bytes = new byte[bufferSize];
while ((bytesRead = inStream.Read(bytes, 0, bufferSize)) > 0)
{
fileStream.Write(bytes, 0, bytesRead);
}
}
}
Run Code Online (Sandbox Code Playgroud)
你永远无法用你自己的代码做一些如此有趣的事情来击败操作系统,即使你在汇编程序中仔细精心制作它也是如此.
如果您需要确保您的操作以最佳性能发生并且您希望混合和匹配各种源,那么您将需要创建一个描述资源位置的类型.然后,您创建一个具有诸如Copy
两种类型的函数的API,并检查两者的描述,选择性能最佳的复制机制.例如,确定两个位置都是Windows文件位置后,它会选择File.Copy OR,如果源是Windows文件,但目标是HTTP POST,则它使用WebRequest.
归档时间: |
|
查看次数: |
33874 次 |
最近记录: |