Should nested awaitable operations be awaited? - c#

I have been following this question and I understand the reasons behind the popular (albeit as-yet-unaccepted) answer by Peter Duniho. Specifically, I am aware that not awaiting a subsequent long-running operation will block the UI thread:
The second example does not yield during the asynchronous operation. Instead, by getting the value of the content.Result property, you force the current thread to wait until the asynchronous operation has completed.
I've even confirmed this, for my own benefit, like so:
private async void button1_Click(object sender, EventArgs e)
{
var value1 = await Task.Run(async () =>
{
await Task.Delay(5000);
return "Hello";
});
//NOTE: this one is not awaited...
var value2 = Task.Run(async () =>
{
await Task.Delay(5000);
return value1.Substring(0, 3);
});
System.Diagnostics.Debug.Print(value2.Result); //thus, UI freezes here after 5000 ms.
}
But now I'm wondering: do you need to await all "awaitable" operations nested within an outermost awaitable operation? For example, I can do this:
private async void button1_Click(object sender, EventArgs e)
{
var value0 = await Task.Run(() =>
{
var value1 = new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
var value2 = new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1.Result);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
Or I can do this:
private async void button1_Click(object sender, EventArgs e)
{
//This time the lambda is async...
var value0 = await Task.Run(async () =>
{
//we're awaiting here now...
var value1 = await new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
//and we're awaiting here now, too...
var value2 = await new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
And neither of them freeze the UI. Which one is preferable?

The last one is preferable (although quite messy)
In TAP (Task-based Asynchronous Pattern) A task (and other awaitables) represent an asynchronous operation. You have basically 3 options of handling these tasks:
Wait synchronously (DoAsync().Result, DoAsync().Wait()) - Blocks the calling thread until the task is completed. Makes your application more wasteful, less scalable, less responsive and susceptible to deadlocks.
Wait asynchronously (await DoAsync()) - Doesn't block the calling thread. It basically registers the work after the await as a continuation to be executed after the awaited task completes.
Don't wait at all (DoAsync()) - Doesn't block the calling thread, but also doesn't wait for the operation to complete. You are unaware of any exceptions thrown while DoAsync is processed
Specifically, I am aware that not awaiting a subsequent long-running operation will block the UI thread
So, Not quite. If you don't wait at all, nothing will block but you can't know when or if the operation completed successfully. However, if you wait synchronously you will block the calling thread and you may have deadlocks if you're blocking the UI thread.
Conclusion: You should await your awaitables as long as that's possible (it isn't in Main for example). That includes "nested async-await operations".
About your specific example: Task.Run is used to offload CPU-bound work to a ThreadPool thread, which doesn't seem to be what you are trying to mimic. If we use Task.Delay to represent a truly asynchronous operation (usually I/O-bound) we can have "nested async-await" without Task.Run:
private async void button1_Click(object sender, EventArgs e)
{
var response = await SendAsync();
Debug.WriteLine(response);
}
async Task<Response> SendAsync()
{
await SendRequestAsync(new Request());
var response = await RecieveResponseAsync();
return response;
}
async Task SendRequestAsync(Request request)
{
await Task.Delay(1000); // actual I/O operation
}
async Task<Response> RecieveResponseAsync()
{
await Task.Delay(1000); // actual I/O operation
return null;
}
You can use anonymous delegates instead of methods, but it's uncomfortable when you need to define the types and invoke them yourself.
If you do need to offload that operation to a ThreadPool thread, just add Task.Run:
private async void button1_Click(object sender, EventArgs e)
{
var response = await Task.Run(() => SendAsync());
Debug.WriteLine(response);
}

Related

not understanding of async await concept [duplicate]

This question already has an answer here:
Async Await Running Synchronously
(1 answer)
Closed 2 years ago.
I do not understand when I read the Microsoft documents about async and await working, as it says
Async methods are intended to be non-blocking operations. An await
expression in an async method doesn’t block the current thread while
the awaited task is running. Instead, the expression signs up the rest
of the method as a continuation and returns control to the caller of
the async method.
so consider my code:
public Form1()
{
InitializeComponent();
AsyncTest();
Test(1);
}
private async void AsyncTest()
{
HttpClient client = new HttpClient();
var ss = TT(2);
var s = await ss;
for (int i = 0; i < 10; i++)
{
//loop
}
}
private async Task<int> TT(int i)
{
while (true)
{
if (i > 1000000000)
break;
i++;
}
return i;
}
}
when ever I call AsyncTest(), it just waits behind TT method as it specified with await key, but what does it mean it return control to the main caller??
it is not been returned to the form1, if TT is an infinite loop it just remains forever.
thanks
It seems to me you are a newbee to async-await. You violate several rules about how to use async-await.
To make a function async do the following:
Declare the function async
Return Task<TResult> instead of TResult; return Task instead of void
ONLY EXCEPTION: event handlers return void instead of Task
there should be one await inside your async function. Your compiler will warn you if you omit this.
Make sure that all async functions that you call are awaited for before you return
Guideline: let async be a suffix to your async functions. This allows you to create a sync and an async function that do the same: void MyTest() and Task MyTestAsync()
Following these rules, you can't call an async function from within a constructor. As you are using Winforms your code could be like this:
public Form1()
{
InitializeComponent();
}
public async void OnButton1_Clicked(object sender, ...)
{ // because this is an event handler the return value is void
// Start the first test and await until ready
await TestAsync();
// Start the second test and await until ready:
int i = await TestAsync(1);
}
If you call an async function you know that somewhere inside this function is an await. If you have meaningful things to do while the inner function is awaiting, do not await yet. Do your useful things after the call and await the returned Task as soon as you need the result:
public async void OnButton2_Clicked(object sender, ...)
{
// Start a test, but don't await yet
var task1 = TestAsync(1);
// if here, function TestAsync is awaiting somewhere
// it is not finished yet, so you can't use the result of it
// But you can do Something else:
DoSomethingElse();
// if here you really need the result of TestAsync, await for it
int i = await task1;
// if here you know that TestAsync is finished, i has the proper return value
}
You don't have to start and await the tasks one by one, you can start several tasks and await for them as soon as you need the results:
public async void OnButton3_Clicked(object sender, ...)
{
// start several tasks. Don't await yet:
var task1 = TestAsync(1);
var task2 = TestAsync(2);
var task3 = TestAsync(3);
DoSomethingElse();
// if here I need the results of all three tasks:
var myTasks = new Task[] {task1, task2, task3};
await Task.WhenAll(myTasks);
}
An article that really helped me understanding async-await is this interview with Eric Lippert, where he compares async-await with a cook making breakfast. If a cook has to wait for the water to boil, he doesn't wait idly, but looks around to see if he can do other things. Search somewhere in the middle for async-await.
Another article that helped me following the guidelines of async-await is Async and Await by the ever so helpful Stephen Cleary

Nested await or async's "glutting"

Let's consider the next procedures hierarhy
Main.cs:
// timer callback
{
Plot.UpdateData();
}
Plot.cs:
public async void UpdateData()
{
await CalculateData();
// ...
}
private async Task CalculateData()
{
await Calculations.Calculate();
// UI updating
// ...
}
Calculations.cs:
public static async Task<bool> Calculate()
{
async Task<bool> CalculateLR()
{
var task1 = Calculate1();
var task2 = Calculate2();
await Task.WhenAll(new[] { task1, task2 });
return true;
}
var leftTask = CalculateLR();
var rightTask = CalculateLR();
await Task.WhenAll(new[] { leftTask, rightTask });
await Calculate3();
return true;
}
Here I have some basic calculations (in Calculate1-Calculate3 procedures) of Calculations.cs file and some interaction with UI. The "entry point" Plot.UpdateData is placed in Device.StartTimer( block of the main form.
It works, but I think this structure creates excess threads. So my question is can this hierarhy be optimized without loss of asynchronous advantages?
Or, other words, which procedures should be awaited in case of nested calls. Where is first non-awaited call should lie? Thanks.
First thing to note: async/await is about tasks, not threads. Under certain circumstances, a task can be thread equivalent, and in most cases it is not (the same thread can serve a lot of tasks sequentially conveyor-style, depending on how they're scheduled for continuation and what is awaiting condition, for example).
And I could strongly recommend to address this for further reading as very comprehensive source:
https://blog.stephencleary.com/2013/11/there-is-no-thread.html
https://blog.stephencleary.com/2014/05/a-tour-of-task-part-1-constructors.html

WhenAll() not working as expected

I need to make UI thread wait until a task array completes execution.The problem with below code is that - the tasks inturn invoke UI thread to write into textbox. How to fix this?
public partial class FormConsole : Form
{
public FormConsole()
{
InitializeComponent();
}
void txtSayHello_Click(object sender, EventArgs e)
{
Class1 objclss = new Class1();
objclss.formConsole = this;
Task[] taa = new Task[4];
taa[0] = new Task(() => objclss.DoSomeThigs("Hello world"));
taa[1] = new Task(() => objclss.DoSomeThigs("Hello world1"));
taa[2] = new Task(() => objclss.DoSomeThigs("Hello world2"));
taa[3] = new Task(() => objclss.DoSomeThigs("Hello world3"));
foreach(Task task in taa)
{
task.Start();
}
Task.WhenAll(taa);
this.txtConsole.AppendText("All threads complete");
}
delegate void doStuffDelegate(string value);
public void doStuff(string value)
{
if (System.Windows.Forms.Form.ActiveForm.InvokeRequired && IsHandleCreated)
{
BeginInvoke(new doStuffDelegate(doStuff), value);
}
else
txtConsole.AppendText(value);
}
}
public class Class1
{
public FormConsole formConsole;
public void DoSomeThigs(string sampleText)
{
formConsole.doStuff(sampleText);
}
}
o/p now : Console Redirection TestAll threads completeHello worldHello world1Hello world2Hello world3
o/p I want : Console Redirection TestHello worldHello world1Hello world2Hello world3All threads complete
What's the solution?
Task.WhenAll returns a task that completes when all tasks passed to it complete. You have to await this task, otherwise the method will continue executing.
async void txtSayHello_Click(object sender, EventArgs e)
{
...
await Task.WhenAll(taa);
...
}
There is a blocking version of this method - Task.WaitAll. It will block the current thread until all tasks are done, but it's not a good idea to block the UI thread.
Also, the preferred way to start a task on a thread pool thread is to use Task.Run.
Task.WhenAll returns a Task representing the completion of all these tasks in the enumerable. You need to await that task as the method doesn't block the thread.
Turn txtSayHello_Click into an async void (which should only be used for event handlers) method and await the task returned from Task.WhenAll:
async void txtSayHello_Click(object sender, EventArgs e)
{
// ...
await Task.WhenAll(taa);
// ...
}
Moreover, you should almost always avoid using the Task constructor. You should use Task.Factory.StartNew with TaskScheduler.FromSynchronizationContext if you need the task to run on the UI thread (that depends on what you actually do with FormConsole) or Task.Run if you don't. Meaning:
taa[0] = Task.Factory.StartNew(() => objclss.DoSomeThigs("Hello world"), CancellationToken.None, TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
Or:
taa[0] = Task.Run(() => objclss.DoSomeThigs("Hello world"));
You're most likely confusing WhenAll() with WaitAll().
As already suggested you can use async with await or you can simply use :
A) Task.WhenAll(taa).Wait();
B) Task.WaitAll(taa);
But in your case this will block UI thread. So it's better to put rest of the code to Continuation Task and invoke UI operations with Control.Invoke() :
Task.WhenAll(taa).ContinueWith(t =>
{
this.Invoke(() => this.txtConsole.AppendText("All threads complete"));
});

using async and await

public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await _domainModel.Load(_State, ProgressIndicatorViewModel); //returns a task
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
ProgressIndicatorViewModel.Stop();
DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
}
i would like to make the two methods (1.domaminModel.Load(), 2. UpdateState()) to run on the same thread one after the other. not on the UI thread.
how can i do this?
i would like to make the two methods (1.domaminModel.Load(), 2.
UpdateState()) to run on the same thread one after the other. not on
the UI thread.
Updated, if you want only _domainModel.Load and ImageSelectionViewModel.UpdateState to run on a separate non-UI thread, then just do this:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Run(async () =>
{
await _domainModel.Load(_State, ProgressIndicatorViewModel))
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
});
ProgressIndicatorViewModel.Stop();
ImageSelectionViewModel.RefreshImages(_imageList);
}
Note you do not need DispatcherHelper.UIDispatcher.Invoke() wrapper then.
If you want the rest of InitData after _domainModel.Load to run on a separate thread:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Run(() => _domainModel.Load(_State,
ProgressIndicatorViewModel)).ConfigureAwait(false);
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
DispatcherHelper.UIDispatcher.Invoke(() =>
{
ProgressIndicatorViewModel.Stop();
ImageSelectionViewModel.RefreshImages(_imageList)
});
}
Note that Task.Run will automatically unwrap the nested task (of Task<Task<T>>) for your here. Also, you'd probably need to move ProgressIndicatorViewModel.Stop() inside Dispatcher.Invoke.
Depending on what's inside _domainModel.Load, you may not even need Task.Run:
await _domainModel.Load(_State,
ProgressIndicatorViewModel).ConfigureAwait(false);
One a side note, you should probably handle exceptions inside your async void InitData method. You won't be able to handle them outside it.
Consider following codes:
public async void Sample()
{
DoOne();
await DoTwo();
DoThree();
Dispather.BeginInvoke(() => DoFour());
}
DoOne Will not executed in UI Thread (!), its thread will be a thread that is a caller of method Sample() named Caller Thread
In most cases in client side the Caller thread is UI Thread, because most codes are invoked by user actions (such as mouse click), but it's not a fixed behavior.
DoTwo will be executed in a separated thread, it's clear that it will not be executed in caller thread.
DoThree will be executed in a Caller Thread
and DoFour will be executed at UI Thread, it does not matter that what's a caller thread.
So the comment of #usr is totally wrong.
To achieve your goal change your code as following:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Factory.StartNew(() => {
_domainModel.Load(_State, ProgressIndicatorViewModel).ContinueWith(() => {
ImageSelectionViewModel.UpdateState(_State); });
};
ProgressIndicatorViewModel.Stop();
DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
}

Can the last await be replaced with an explicit wait?

I'm still learning the async/await, so please excuse me if I'm asking something obvious. Consider the following example:
class Program {
static void Main(string[] args) {
var result = FooAsync().Result;
Console.WriteLine(result);
}
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = await t2;
return result1 + result2;
}
static Task<int> Method1Async() {
return Task.Run(
() => {
Thread.Sleep(1000);
return 11;
}
);
}
static Task<int> Method2Async() {
return Task.Run(
() => {
Thread.Sleep(1000);
return 22;
}
);
}
}
This behaves as expected and prints "33" in the console.
If I replace the second await with an explicit wait...
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = t2.Result;
return result1 + result2;
}
...I seem to get the same behavior.
Are these two examples completely equivalent?
And if they are equivalent in this case, are there any other cases where replacing the last await by an explicit wait would make a difference?
Your replacement version blocks the calling thread waiting for the task to finish. It's hard to see a visible difference in a console app like that since you're intentionally blocking in Main, but they're definitely not equivalent.
They are not equivalent.
Task.Result blocks until the result is available. As I explain on my blog, this can cause deadlocks if you have an async context that requires exclusive access (e.g., a UI or ASP.NET app).
Also, Task.Result will wrap any exceptions in AggregateException, so error handling is harder if you synchronously block.
OK, I think I figured this out so let me sum it up, in what will hopefully be a more complete explanation than the answers provided so far...
Short Answer
Replacing the second await with an explicit wait will have no appreciable effect on a console application, but will block the UI thread of a WPF or WinForms application for the duration of the wait.
Also, the exception handling is slightly different (as noted by Stephen Cleary).
Long Answer
In a nutshell, the await does this:
If the awaited task has already finished, it just retrieves its result and continues.
If it hasn't, it posts the continuation (the rest of the method after the await) to the current synchronization context, if there is one. Essentially, await is trying to return us where we started from.
If there isn't a current context, it just uses the original TaskScheduler, which is usually thread pool.
The second (and third and so on...) await does the same.
Since the console applications typically have no synchronization context, continuations will typically be handled by the thread pool, so there is no issue if we block within the continuation.
WinForms or WPF, on the other hand, have synchronization context implemented on top of their message loop. Therefore, await executed on a UI thread will (eventually) execute its continuation on the UI thread as well. If we happen to block in the continuation, it will block the message loop and make the UI non-responsive until we unblock. OTOH, if we just await, it will neatly post continuations to be eventually executed on the UI thread, without ever blocking the UI thread.
In the following WinForms form, containing one button and one label, using await keeps the UI responsive at all times (note the async in front of the click handler):
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e) {
var result = await FooAsync();
label1.Text = result.ToString();
}
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = await t2;
return result1 + result2;
}
static Task<int> Method1Async() {
return Task.Run(
() => {
Thread.Sleep(3000);
return 11;
}
);
}
static Task<int> Method2Async() {
return Task.Run(
() => {
Thread.Sleep(5000);
return 22;
}
);
}
}
If we replaced the second await in FooAsync with t2.Result, it would continue to be responsive for about 3 seconds after the button click, and then freeze for about 2 seconds:
The continuation after the first await will politely wait its turn to be scheduled on the UI thread, which would happen after Method1Async() task finishes, i.e. after about 3 seconds,
at which point the t2.Result will rudely block the UI thread until the Method2Async() task finishes, about 2 seconds later.
If we removed the async in front of the button1_Click and replaced its await with FooAsync().Result it would deadlock:
The UI thread would wait on FooAsync() task to finish,
which would wait on its continuation to finish,
which would wait on the UI thread to become available,
which it isn't, since it is blocked by the FooAsync().Result.
The article "Await, SynchronizationContext, and Console Apps" by Stephen Toub was invaluable to me in understanding this subject.

Categories