Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async/await and opening a FileStream?

Tags:

I came across the following question when trying to determine if I was using the Stream methods such as ReadAsync and CopyToAsync correctly: C# 4.5 file read performance sync vs async

In this question I read the following in the accepted answer:

Most notably, your "async" test does not use async I/O; with file streams, you have to explicitly open them as asynchronous or else you're just doing synchronous operations on a background thread.

In his asynchronous IO code he was using the following to open the FileStream 'asynchronously':

var file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true) 

So I was wondering if you intend to use methods such as CopyToAsync whether you should open the underlying FileStream as shown above?, as opposed to doing something simple like the following:

File.Open(filename, FileMode.Open) 

Which is how the example in the actual documentation for CopyToAsync demonstrates opening the underlying FileStream: https://msdn.microsoft.com/en-us/library/hh159084(v=vs.110).aspx

If it does not matter which way the underlying FileStream is opened, what does the useAsync parameter of the FileStream constructor do?

like image 206
Alex Hope O'Connor Avatar asked May 05 '16 03:05

Alex Hope O'Connor


People also ask

Does async await start a new thread?

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.

When should I use async await C#?

If the work you have is I/O-bound, use async and await without Task. Run . You should not use the Task Parallel Library. If the work you have is CPU-bound and you care about responsiveness, use async and await , but spawn off the work on another thread with Task.

Should async method return task?

For methods other than event handlers that don't return a value, you should return a Task instead, because an async method that returns void can't be awaited. Any caller of such a method must continue to completion without waiting for the called async method to finish.

Can an async method run on the UI thread of a Windows Forms app?

You can start an async operation from the UI thread, await it without blocking the UI thread, and naturally resume on the UI thread when it's done. This is a very powerful feature, and most of the time you don't even need to think about it; it “just works”.


2 Answers

So I was wondering if you intend to use methods such as CopyToAsync whether you should open the underlying FileStream as shown above?

Yes. The reason is mostly historical.

First, on Windows, HANDLEs (including file handles) must be opened/created explicitly with an asynchronous flag if you want to do asynchronous (OVERLAPPED) operations on them.

However, the old Windows 95/98/ME line only supported asynchronous operations on serial port and IOCTL (device driver) handles. Asynchronous I/O on disk files wasn't supported on that platform line. And the original .NET did support 98/ME, so the original FileStream just used synchronous I/O. I think (but am not absolutely sure) that APM methods (like FileStream.BeginRead) on Win98/ME were probably just implemented using the so-called "asynchronous delegates" (which just execute a synchronous method like FileStream.Read on a thread pool thread).

So, that's the historical reason why file stream handles were not opened with the asynchronous flag by default.

Which is how the example in the actual documentation for CopyToAsync demonstrates

Unfortunately, a lot of the MSDN examples are rather poor quality. They're OK if you approach them from the perspective of "here's an example of how to call this specific method", but not so great from the perspective of "here's an example of production-quality code that uses this method".

like image 73
Stephen Cleary Avatar answered Oct 23 '22 20:10

Stephen Cleary


So I was wondering if you intend to use methods such as CopyToAsync whether you should open the underlying FileStream as shown above, as opposed to doing something simple like File.Open?

I used ILSpy to decompile and look at File.Open.

public static FileStream Open(string path, FileMode mode) {     return File.Open(path,                       mode,                       (mode == FileMode.Append)                           ? FileAccess.Write                           : FileAccess.ReadWrite,                       FileShare.None); } 

Which calls this:

public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share) {     return new FileStream(path, mode, access, share); } 

And this specific FileStream constructor passes in false for the useAsync parameter. So, yes it appears to matter. However, you can still invoke the async APIs and it will still work as you'd expect.

As Hans Passant states:

The underlying CreateFile() call then uses the FILE_FLAG_OVERLAPPED option. This enables overlapped I/O, a mechanism that enables asynchronous reads and writes at the winapi level.

The FileStream class has an _isAsync bool, and it means "If async IO is not supported on this platform or if this FileStream was not opened with FileOptions.Asynchronous.".

Again, you still get a Task that represents that asynchronous operation as you desire.

like image 28
David Pine Avatar answered Oct 23 '22 20:10

David Pine