我需要对同一个文件进行一批写操作,但是要在文件中的不同位置。我希望以最佳性能实现这一点,因此查看了同步FileStream.Write和异步FileStream.BeginWrite方法。
同步实现很简单,只需在循环中调用FileStream.Write所需的次数即可。异步版本在循环中调用FileStream.BeginWrite,然后执行WaitHandle.WaitAll以阻止它们全部完成。令我惊讶的是,这比简单的同步版本慢。
我使用正确的构造函数创建了FileStream,因此我可以请求异步操作,并且还测试了指示False的IAsyncResult.CompletedSynchronous属性,因此它们确实以异步方式运行。似乎使用BeginWrite的唯一好处是你在写入时不会阻塞你的线程。除了这个好处之外,使用异步版本有什么意义吗?
这是我用于播放异步方法的测试代码,可能有一个明显的错误?
// 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();
答案 0 :(得分:20)
在Windows中对文件写入进行了大量优化。您实际上没有写入磁盘,而是写入文件系统缓存。内存到内存的副本,以每秒5千兆字节或更高的速度运行。然后,从缓存中,数据被懒惰地写入磁盘。反过来优化,以尽量减少写头移动的次数。
这几乎不可能通过异步写入进行优化。确实需要更长的时间,抓住线程池线程以使回调不是免费的。这里异步的好处是最小化主线程延迟,而不是实际上使其更有效。只有在编写大量数据时才能获得实惠。不仅适合缓存。此时,写入perf将从5 GB /秒下降到小于~50 MB /秒的悬崖,因为缓存空间只能以可写入磁盘的速率变为可用。
究竟何时发生这种情况很难预测。这取决于机器有多少RAM以及其他进程需要多少RAM。当你写一千兆字节或更少时,你基本上不用担心它。当异步写入挂起时,实际上有一些有用的事情是很重要的。等待他们完成就无法使用它。