10

I'm using the following C# code to read a tiny text file over a network share:

string fileContent;
using (var stream = File.OpenRead(filePath))
using (var reader = new StreamReader(stream, FileEncoding))
{
    fileContent = await reader.ReadToEndAsync();
}

Even though the text file is very small (less than 10 KB) this operation sometimes takes ~7 seconds to run. When that happens, I've noticed most of the time is spent on

File.OpenRead(filePath)

This is probably due to Windows having to resolve the file share and to acquire locks on the file over the network. As that method call is not asynchronous, this is blocking my current thread for several seconds.

Is there a safe way to read a file from disk asynchronously that also performs OpenRead asynchronously?

svick
  • 236,525
  • 50
  • 385
  • 514
roim
  • 4,780
  • 2
  • 27
  • 35
  • Have you tried copying or moving the file to local first and then reading it? Just try it if you haven't already to test it, that may show some other possible problem in network if that is the case. – Oğuz Sezer Apr 02 '15 at 11:09

1 Answers1

18

No, unfortunately this is missing in the Win32 API. Device drivers do have the notion of an "asynchronous open", so the infrastructure is there; but the Win32 API does not expose this functionality.

Naturally, this means that .NET can't expose that functionality, either. You can, however, use a "fake asynchronous" operation - i.e., wrap your file read within a Task.Run, so that your UI thread isn't blocked. However, if you're on ASP.NET, then don't use Task.Run; just keep the (blocking) file open as it is.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 2
    HOLY CRAP. Is there a voice to get that added to the Win 10 API? – Aron Apr 02 '15 at 01:50
  • I'm not on ASP.NET, but I would be interested in knowing why that would be a bad choice there specifically. Any references? – roim Apr 02 '15 at 03:31
  • @aron: Not to my knowledge; feel free to open a UserVoice issue. I believe that async close is also possible, but may be more difficult to model. – Stephen Cleary Apr 02 '15 at 10:10
  • @roim: The main goal of `async` on a client UI is to free up the UI thread so the app is more responsive; it's acceptable (but not ideal) to use `Task.Run`, which just blocks a thread pool thread so the UI thread is not blocked. – Stephen Cleary Apr 02 '15 at 10:12
  • 9
    @roim: The main goal of `async` on ASP.NET is to free up thread pool threads so the server can scale; using `Task.Run`, would force a context switch and then use up one thread pool thread to free up another thread pool thread. A net loss. I've written about it a bit [in an MSDN article](https://msdn.microsoft.com/en-us/magazine/dn802603.aspx) and [on my blog](http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html). – Stephen Cleary Apr 02 '15 at 10:15
  • I asked a follow up question based on your answer as the documentation for the 'Async' IO methods showed opening the filestream without specifying the useAsync parameter: http://stackoverflow.com/questions/37041844/c-sharp-async-await-and-opening-a-filestream – Alex Hope O'Connor May 05 '16 at 03:33