-1

Just a confirmation if I got it right because I couldn't find a definitive answer to this:

private async void button_click()
{
    await DoWork();

    Textbox.Text = "Hello World";
}

private async void button_click()
{
    var ret = await DoWork();

    Textbox.Text = "Hello World";
}

private async Task<int> DoWork()
{
     int ret = 0;

     ret = await WriteToDiskAsync();

     return ret;
}

If I assign the return value of the async method to a variable, I'm 100% sure that the Textbox.Text assignment is done after DoWork() completes, even if what follows does not use the ret variable. While in the first example is uncertain if Textbox.Text assignment is done after DoWork() completes, because the UI thread is not suspended and the flow continues, so depending on the amount of work of DoWork() and the scheduler anything could happen.

I thought await meant what it means in the natural language...wait, but is not like that.

Alberto Rivelli
  • 1,953
  • 2
  • 15
  • 19
  • if you have `async void` awaitable is not being awaited. – xZ6a33YaYEfmv Oct 25 '15 at 19:02
  • 1
    Both methods equivalent. And possible, that them produce same IL, as you does not use `ret`. – user4003407 Oct 25 '15 at 19:03
  • @Alberto, I meant `async void` in `async void button_click()`. more [details](http://stackoverflow.com/a/12144426/183267), and [here](http://haacked.com/archive/2014/11/11/async-void-methods/). – xZ6a33YaYEfmv Oct 25 '15 at 19:07
  • @ieaglle please answer the first question am I 100% sure that in the second example the TextBox assignment is done after `DoWork()` completes? – Alberto Rivelli Oct 25 '15 at 19:12
  • @Alberto in both of your example handler text is assigned only after the do work task completes (you could also use only Task without the int part if you do not want to return anything but to be able to await the method) – kirotab Oct 25 '15 at 19:19
  • @kirotab Unfortunately I'm pretty sure from real code that is not like that. – Alberto Rivelli Oct 25 '15 at 19:26
  • @Alberto Maybe show the exact line where you call and await the async method in the "real code" that you refer to because it doesn't seem right if these awaits are not doing their job :) – kirotab Oct 25 '15 at 19:30
  • @Alberto I am just compile your code and decompile it in ILSpy. Both methods produce almost identical IL. Only difference in `pop` instruction (which ignore result of `await` operation) location. In first case `pop` occurs before awaiter cleanup. In second case after awaiter cleanup. There is no observable difference in behavior. – user4003407 Oct 25 '15 at 19:31
  • @PetSerAl so you're saying that what follows the call to `DoWork()` does not influence code flow: the await always stop execution at that point? – Alberto Rivelli Oct 25 '15 at 20:01
  • @PetSerAl both methods equivalent means that they both always stops at await or they both don't? – Alberto Rivelli Oct 25 '15 at 20:15
  • 1
    @Alberto Code after `await` executed only after awaited operation complete. – user4003407 Oct 25 '15 at 20:19
  • I think the problem is with `Textbox.Text = "Hello World";` called inside an non-UI thread. I don't see any other problems. – W0lfw00ds Oct 25 '15 at 20:39
  • @AshtonWoods why should that be a problem? I think that line is actually executed by the UI thread when it's resumed. – Alberto Rivelli Oct 25 '15 at 21:10

2 Answers2

2

If I assign the return value of the async method to a variable, I'm 100% sure that the Textbox.Text assignment is done after DoWork() completes, even if what follows does not use the ret variable. While in the first example is uncertain if Textbox.Text assignment is done after DoWork() completes, because the UI thread is not suspended and the flow continues, so depending on the amount of work of DoWork() and the scheduler anything could happen.

The assignment has nothing to do with control flow. The await is what "yields" the thread, and in both cases the async method continues executing only after DoWork completes. (Technically, in both cases the async method continues executing only after the task returned from DoWork completes).

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Ok so it's like I thought it was and like PetSerAL said in his first comment. But I'm still not convinced that this is guaranteed in reality, there so many things going on under the hood, so many threads we can't control... – Alberto Rivelli Oct 25 '15 at 21:18
  • @Alberto: Tasks complete exactly once, and when they complete, they schedule all their continuations. `await` breaks up an `async` method into multiple "chunks" - each `await` is a "break". When you `await` a task (assuming the task is not *already* complete), the `await` operator merely attaches the next "chunk" as a continuation on that task. So it's actually straightforward to guarantee this. It doesn't matter how the async method is implemented, or how many threads, or where it runs (UI/threadpool). When that task completes, the method continues *because it's a continuation for that task*. – Stephen Cleary Oct 25 '15 at 21:56
0

From my comment

@Alberto in both of your example handler text is assigned only after the do work task completes (you could also use only Task without the int part if you do not want to return anything but to be able to await the method)

However I've seen a possible issue with the code, if your method:

private async Task<int> DoWork()
{
     //Unknown code
}

does not contain anything awaited inside the compiler will want you that it's going to be run synchronous so it should actually block your thread in my opinion.

I was terribly wrong about this so I've stroked it out to not confuse anyone else.

Please try with the following code if it's not behaving asynchronously :)

private async Task DoWork()
{
     //awaits 1 millisecond to trick the method to be really asynchronous
     await Task.Delay(1);
}

kirotab
  • 1,296
  • 1
  • 11
  • 18
  • I wanted to keep things simple but of course there's a long async operation in the `DoWork()` method. I changed it with a write to disk. Please update your answer, you are saying that in both versions the TextBox is assignment is done 100% sure after `DoWork()` completes, right? Are you sure 100%? – Alberto Rivelli Oct 25 '15 at 19:32
  • @Alberto Ah i see, but even if it was the case it should have behaved the same way but to block the ui and wait the operation to finish. Please paste the row when you await your long operation if possible, sometimes when using multiple async operations it might be a matter of using brackets. – kirotab Oct 25 '15 at 19:35
  • There is tons of code I can't paste all the stack, the `await WriteToDiskAsync();` is equivalent. I edited it because I'm really using the return value. – Alberto Rivelli Oct 25 '15 at 19:39
  • Maybe somewhere deeper in your method you have async void method as "ieaglle" suggested and it starts long operation that is not awaited, do you have nested async methods ? – kirotab Oct 25 '15 at 19:43
  • @Alberto Maybe try to debug the code -> put a long delay at the end of your long operation with await, then put a break point where you call DoWork(); press step over when you get there and see if Textbox.Text = "Hello World"; is executed before DoWork finishes (if that's the case you'll need an exorcist :) ) – kirotab Oct 25 '15 at 19:52
  • I double checked and I'm sure there are no `async void` calls in the call stack, I only use async void in controls event handlers – Alberto Rivelli Oct 25 '15 at 20:07