Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FileStream WriteAsync and await confusion

I'm looking at the new async and await keywords in C# and just trying to get a feel for them.

I'm looking at the MSDN FileStream.WriteAsync() example, and I wasn't sure I understood something.

The example is as follows:

using System;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.IO;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            UnicodeEncoding uniencoding = new UnicodeEncoding();
            string filename = @"c:\Users\exampleuser\Documents\userinputlog.txt";

            byte[] result = uniencoding.GetBytes(UserInput.Text);

            using (FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate))
            {
                SourceStream.Seek(0, SeekOrigin.End);
                await SourceStream.WriteAsync(result, 0, result.Length);
            }
        }
    }
}

What I don't get is the placement of the await. It seems that you can't take the Task item that is returned by WriteAsync() because this always gives me a syntax error. So the only way I could get this to compile is by leaving the await with the call.

But if you do this, does it not wait for the call to finish? This makes it not very asynchronous...

like image 377
poy Avatar asked Dec 12 '12 13:12

poy


2 Answers

I suspect the problem is with your understanding of what await does.

But if you do this, does it not wait for the call to finish? This makes it not very asynchronous...

When you await something, you "block asynchronously" - your asynchronous function will continue when the asynchronous operation has completed, but the immediate call will complete immediately.

So in your case, the UI thread becomes unblocked because Button_Click returns, but when the file write operation has completed, execution will return (still in the UI thread) to the end of the await expression... you'll then close the FileStream and complete the asynchronous function.

It would be clearer what was going on if you did something else after the await expression (e.g. updating the UI). But yes, it really is asynchronous - it just allows you to write code which looks synchronous.

like image 173
Jon Skeet Avatar answered Oct 09 '22 19:10

Jon Skeet


The await doesn't actually block while it's waiting. What happens is that the compiler does some complex stuff to make a so called continuation of all code after the await and tells the task to execute that continuation when it's completed.

Basically the last lines of the Button_Click method are translated to:

FileStream SourceStream = File.Open(filename, FileMode.OpenOrCreate);
SourceStream.Seek(0, SeekOrigin.End);
Task t = SourceStream.WriteAsync(result, 0, result.Length);
t.ContinueWith(_ => SourceStream.Dispose());

Of course, this is simplified as this will be executed more efficient if the WriteAsync completes immediately, for example.

like image 20
Patrick Huizinga Avatar answered Oct 09 '22 18:10

Patrick Huizinga