FileStream.BeginWrite优于FileStream.Write?

时间:2011-10-11 23:15:03

标签: c# .net asynchronous filestream

我需要对同一个文件进行一批写操作,但是要在文件中的不同位置。我希望以最佳性能实现这一点,因此查看了同步FileStream.Write和异步FileStream.BeginWrite方法。

同步实现很简单,只需在循环中调用FileStream.Write所需的次数即可。异步版本在循环中调用FileStream.BeginWrite,然后执行WaitHandle.WaitAll以阻止它们全部完成。令我惊讶的是,这比简单的同步版本慢。

我使用正确的构造函数创建了FileStream,因此我可以请求异步操作,并且还测试了指示False的IAsyncResult.CompletedSynchronous属性,因此它们确实以异步方式运行。似乎使用Be​​ginWrite的唯一好处是你在写入时不会阻塞你的线程。除了这个好处之外,使用异步版本有什么意义吗?

这是我用于播放异步方法的测试代码,可能有一个明显的错误?

        // Size of a chunk to be written to file
        var chunk = 1024 * 64;

        // Number of chunks to write async
        var reps = 32;

        // Create new file and set length
        var fs = new FileStream(@"C:\testfile.dat", 
                                FileMode.Create, FileAccess.ReadWrite, 
                                FileShare.None, chunk, true);
        fs.SetLength(chunk * reps);

        // Allocate resources
        byte[] bytes = new byte[chunk];
        WaitHandle[] handles = new WaitHandle[reps];

        for (int i = 0; i < reps; i++)
        {
            fs.Seek(chunk * i, SeekOrigin.Begin);
            handles[i] = fs.BeginWrite(bytes, 0, chunk, null, null).AsyncWaitHandle;
        }

        // Wait for all async operations to complete
        WaitHandle.WaitAll(handles);

        fs.Flush();
        fs.Close();

1 个答案:

答案 0 :(得分:20)

在Windows中对文件写入进行了大量优化。您实际上没有写入磁盘,而是写入文件系统缓存。内存到内存的副本,以每秒5千兆字节或更高的速度运行。然后,从缓存中,数据被懒惰地写入磁盘。反过来优化,以尽量减少写头移动的次数。

这几乎不可能通过异步写入进行优化。确实需要更长的时间,抓住线程池线程以使回调不是免费的。这里异步的好处是最小化主线程延迟,而不是实际上使其更有效。只有在编写大量数据时才能获得实惠。不仅适合缓存。此时,写入perf将从5 GB /秒下降到小于~50 MB /秒的悬崖,因为缓存空间只能以可写入磁盘的速率变为可用。

究竟何时发生这种情况很难预测。这取决于机器有多少RAM以及其他进程需要多少RAM。当你写一千兆字节或更少时,你基本上不用担心它。当异步写入挂起时,实际上有一些有用的事情是很重要的。等待他们完成就无法使用它。