C# 非托管文件访问(WriteFile)比托管文件(FileStream)慢

C# 非托管文件访问(WriteFile)比托管文件(FileStream)慢,c#,file-io,visual-studio-2012,unmanaged,managed,C#,File Io,Visual Studio 2012,Unmanaged,Managed,我有一个大量读取和写入文件(自定义格式)的应用程序,有人告诉我通过使用直接非托管代码来提高性能。 在尝试在实际应用程序中使用之前,我做了一个小测试,只是想看看性能会有怎样的提高,但出乎意料的是,非托管版本似乎比简单使用filestream慢8倍 以下是托管功能: private int length = 100000; private TimeSpan tspan; private void UsingManagedFileHandle() {

我有一个大量读取和写入文件(自定义格式)的应用程序,有人告诉我通过使用直接非托管代码来提高性能。 在尝试在实际应用程序中使用之前,我做了一个小测试,只是想看看性能会有怎样的提高,但出乎意料的是,非托管版本似乎比简单使用filestream慢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";
    }
private int length=100000;
私人时间跨度tspan;
使用ManagedFileHandle()的私有void
{
DateTime initialTime=DateTime.Now;
使用(FileStream FileStream=newfilestream(“data2.txt”、FileMode.Create、FileAccess.ReadWrite))
{
字符串行=“abcdefghijklmnopqrstuvxyz1234567890123”;
byte[]bytes=Encoding.Unicode.GetBytes(第行);
for(int i=0;i
以下是非托管方式:

    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);
使用UnmanagedFileHandle()的公共无效 { 日期时间初始时间; IntPtr-hFile; hFile=IntPtr.Zero; hFile=FileInteropFunctions.CreateFile(“data1.txt”, FileInteropFunctions.GENERIC|u WRITE | FileInteropFunctions.GENERIC_READ, FileInteropFunctions.FILE\u SHARE\u WRITE, IntPtr.Zero, FileInteropFunctions.CREATE_始终, FileInteropFunctions.FILE_属性_正常, 0); uint LPNumberOfBytesWrited=0; initialTime=DateTime.Now; 如果(hFile.ToInt64()>0) { 字符串行=“abcdefghijklmnopqrstuvxyz1234567890123”; byte[]bytes=Encoding.Unicode.GetBytes(第行); uint bytesLen=(uint)bytes.Length; for(int i=0;i 在我的计算机中,使用FileStream的迭代大约需要70毫秒。 使用WriteFile的一个大约需要550ms

我测试了几次,多次迭代,性能上的差异是一致的

我不知道为什么非托管代码比托管代码慢

编辑

非常感谢你们的解释,伙计们。我认为在文件流中有一些“神奇”的东西,你已经解释得很好了。
所以,我知道在这一部分中,要获得性能并不是一条简单的道路,我想请你们对其他提高速度的简单方法发表意见。在实际应用程序中,该文件是随机访问的,大小可能在1MB到1GB之间。

在缓冲FileStream时,您的非托管调用会尽快将数据写入磁盘(即在内存中执行大多数操作,并且应该少调用底层非托管调用)


如果您想进一步调整性能,有一些方法可以让您控制缓冲区大小。

在缓冲FileStream时,您的非托管调用会尽快将数据写入磁盘(即在内存中执行大多数操作,并且应该更少地调用底层非托管调用)


如果您想进一步调整性能,有一些方法可以让您控制缓冲区大小。

区别在于对
WriteFile
的调用是同步的,而对
文件流的写入则不是同步的

默认情况下,
CreateFile
将创建一个同步文件句柄,因此在写入数据之前不会返回对
WriteFile
的调用。如果将
FILE\u FLAG\u OVERLAPPED
添加到
CreateFile
调用中,则非托管实现将花费与托管实现大致相同的时间


请参阅
CreateFile
defini

部分的文档。区别在于对
WriteFile
的调用是同步的,而对
文件流的写入则不是同步的

默认情况下,
CreateFile
将创建一个同步文件句柄,因此在写入数据之前不会返回对
WriteFile
的调用。如果将
FILE\u FLAG\u OVERLAPPED
添加到
CreateFile
调用中,则非托管实现将花费与托管实现大致相同的时间


参见
CreateFile
defini

部分的文档。好吧,FileStream是CreateFile/WriteFile的包装器。这是bu写的