Why does creating a FileStream with FileOptions.Asynchronous cause FileStream.BeginRead to block the calling thread?
Here is the code snippet:
private static Task<int> ReadFileAsync(string filePath)
{
var file = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 64 * 1024, FileOptions.Asynchronous);
FileInfo fi = new FileInfo(filePath);
byte[] buffer = new byte[fi.Length];
Task<int> task = Task<int>.Factory.FromAsync(file.BeginRead, file.EndRead, buffer, 0, buffer.Length, null);
return task.ContinueWith(t =>
{
file.Close();
Console.WriteLine("Done ReadFileAsync, read " + t.Result + " bytes.");
return t.Result;
});
}
When digging around in the MSFT FileStream code using JetBrains dotPeek it seems like there is a bug in their code:
if (!this._isAsync)
return base.BeginRead(array, offset, numBytes, userCallback, stateObject);
else
return (IAsyncResult) this.BeginReadAsync(array, offset, numBytes, userCallback, stateObject);
The BeginRead method actually seems to do reading asynchronously by scheduling a Task, but the BeginReadAsync method actually ends up doing a synchronous read. So their method naming nomenclature is backwards and the logic of which method is called is wrong. BeginRead should be called if this._isAsync == true.
So it seems that to get FileStream.BeginRead to return right away (asynchronously schedule a read) you actually have to set the useAsync parameter in the cosntructor to false.
Here's a knowledge base article that lists all the ways that can cause code you desire to be executed asynchronously to actually run synchronously.
Asynchronous Disk I/O Appears as Synchronous on Windows NT, Windows 2000, and Windows XP
Does anything on the list apply to your situation?
Have you tried implementing the same behavior with .NET 4.5's ReadAsync method?
I am quoting from MSDN:
EDIT I am reproducing your issue with a 256MB file on OCZ Vertex 2 with ICH10 and Windows 7. I am having to generate the file, reboot the PC to clear file cache, and then try and read the same file.
When all else fails, here's the reference to unmanaged API documentation.