我有一个对文件(自定义格式)进行大量读写的应用程序,有人告诉我通过使用直接非托管代码来提高性能。在尝试实际应用程序之前,我做了一个小测试,只是为了看看性能提升如何,但令我惊讶的是,非托管版本似乎比使用简单的文件流慢 8 倍。
这是托管功能:
private int length = 100000;
private TimeSpan tspan;
private void UsingManagedFileHandle()
{
DateTime initialTime = DateTime.Now;
using (FileStream fileStream = new FileStream("data2.txt", FileMode.Create, FileAccess.ReadWrite))
{
string line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890123";
byte[] bytes = Encoding.Unicode.GetBytes(line);
for (int i = 0; i < length; i++)
{
fileStream.Write(bytes, 0, bytes.Length);
}
fileStream.Close();
}
this.tspan = DateTime.Now.Subtract(initialTime);
label2.Text = "" + this.tspan.TotalMilliseconds + " Milliseconds";
}
这是非托管方式:
public void UsingAnUnmanagedFileHandle()
{
DateTime initialTime;
IntPtr hFile;
hFile = IntPtr.Zero;
hFile = FileInteropFunctions.CreateFile("data1.txt",
FileInteropFunctions.GENERIC_WRITE | FileInteropFunctions.GENERIC_READ,
FileInteropFunctions.FILE_SHARE_WRITE,
IntPtr.Zero,
FileInteropFunctions.CREATE_ALWAYS,
FileInteropFunctions.FILE_ATTRIBUTE_NORMAL,
0);
uint lpNumberOfBytesWritten = 0;
initialTime = DateTime.Now;
if (hFile.ToInt64() > 0)
{
string line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890123";
byte[] bytes = Encoding.Unicode.GetBytes(line);
uint bytesLen = (uint)bytes.Length;
for (int i = 0; i < length; i++)
{
FileInteropFunctions.WriteFile(hFile,
bytes,
bytesLen,
out lpNumberOfBytesWritten,
IntPtr.Zero);
}
FileInteropFunctions.CloseHandle(hFile);
this.tspan = DateTime.Now.Subtract(initialTime);
label1.Text = "" + this.tspan.TotalMilliseconds + " Milliseconds";
}
else
label1.Text = "Error";
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe IntPtr CreateFile(
String lpFileName, // Filename
uint dwDesiredAccess, // Access mode
uint dwShareMode, // Share mode
IntPtr attr, // Security Descriptor
uint dwCreationDisposition, // How to create
uint dwFlagsAndAttributes, // File attributes
uint hTemplateFile); // Handle to template file
[DllImport("kernel32.dll")]
public static extern unsafe int WriteFile(IntPtr hFile,
// byte[] lpBuffer,
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer, // also tried this.
uint nNumberOfBytesToWrite,
out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped);
在我的计算机中,使用 FileStream 的迭代大约需要 70 毫秒。使用 WriteFile 大约需要 550 毫秒。
我测试了几次并进行了多次迭代,性能差异是一致的。
我不知道为什么非托管代码比托管代码慢。
编辑
非常感谢你们的解释,伙计们。我认为 FileStream 发生了一些“神奇”的事情,你已经解释得很好。所以,我知道现在在这部分没有简单的方法来提高性能,我想就其他简单的提高速度的方法征求你的意见。该文件在实际应用程序中是随机访问的,大小可以从 1MB 到 1GB 不等。