I'm learning async and await operation in c#. I couldn't understand the flow of execution when it handles multiple async operation. for eg: I have the below code in my c# application.
await repository.GetAsync(values); // execute for 10 sec
var result = repository.setAsync(data); // 20 sec
dataresult = await repository.GetAsync(result); //execute for 10 sec
I have three async calls here.
As per my understanding each call will have a callback and this will not wait for one action to complete.
So how I can ensure the action is complete?
The repository.setAsync will execute before repository.GetAsync(values) complete its execution? or this will execute only after repository.GetAsync(values) execution completed?
So what will be the order of execution?
1)
await repository.GetAsync(values); // started await method execution, since there is no callback it will not set and will start execute the next before complete this.
var result = repository.setAsync(data); // will execute for 20 sec. Once completed will go to previous thread and complete that.
await repository.GetAsync(values); // started await method execution, complete it and move to the next line.
var result = repository.setAsync(data); // will execute for 20 sec.
When you execute something synchronously, you wait for it to finish before moving on to another task. When you execute something asynchronously, you can move on to another task before it finishes. But here, for asynchronous it waiting for the operation to finish. Why this contradiction?
I want to return the dataresult only once the operation has been completed.
I feel this is contrary to fire and forget. Whether these two are same or different concepts?
As per the below link reference
The await keyword does not block the thread until the task is
complete.
But from the answers posted here, I understood this will pause the execution. which is true? Am I missed something?
As per my understanding each call will have a callback and this will not wait for one action to complete.
When you use await, the code will wait for the action to complete before moving on. This is the way you deal with data dependencies -- situations when a task needs results from a previous task to be available before it can start processing. The only action that is not awaited is result, so GetAsync(result) must take Task<T> as its parameter, where T is the type of whatever SetAsync method returns.
Note
If code following the await does not need to be executed on the UI thread you should call ConfigureAwait(false) upon the Task you are awaiting. Why is this best practice? Stephen Cleary provides an excellent blog post on the topic of async/await deadlocks that explains it.
It is also very likely that you are missing await on the second line and an assignment of data on the first line:
var data = await repository.GetAsync(values).ConfigureAwait(false);
var result = await repository.SetAsync(data).ConfigureAwait(false);
dataresult = await repository.GetAsync(result).ConfigureAwait(false);
So what is the concept of callback and fire and forget here?
If callback happens before the call of await, which is possible when you fire up a task, do something else, and then await that task, you get a chance to do more work in between "firing and forgetting" and getting the results back. The key here is that there must be no data dependency in the middle:
var dataTask = repository.GetAsyncOne(values); // Fire and forget
// Do something else in the middle
var result = await repository.SetAsync(data).ConfigureAwait(false);
// If the task has completed, there will be no wait
var data = await dataTask.ConfigureAwait(false);
Related
In terms of performance, will these 2 methods run GetAllWidgets() and GetAllFoos() in parallel?
Is there any reason to use one over the other? There seems to be a lot happening behind the scenes with the compiler so I don't find it clear.
============= MethodA: Using multiple awaits ======================
public async Task<IHttpActionResult> MethodA()
{
var customer = new Customer();
customer.Widgets = await _widgetService.GetAllWidgets();
customer.Foos = await _fooService.GetAllFoos();
return Ok(customer);
}
=============== MethodB: Using Task.WaitAll =====================
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
Task.WaitAll(new List[] {getAllWidgetsTask, getAllFoosTask});
customer.Widgets = getAllWidgetsTask.Result;
customer.Foos = getAllFoosTask.Result;
return Ok(customer);
}
=====================================
The first option will not execute the two operations concurrently. It will execute the first and await its completion, and only then the second.
The second option will execute both concurrently but will wait for them synchronously (i.e. while blocking a thread).
You shouldn't use both options since the first completes slower than the second and the second blocks a thread without need.
You should wait for both operations asynchronously with Task.WhenAll:
public async Task<IHttpActionResult> MethodB()
{
var customer = new Customer();
var getAllWidgetsTask = _widgetService.GetAllWidgets();
var getAllFoosTask = _fooService.GetAllFos();
await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);
customer.Widgets = await getAllWidgetsTask;
customer.Foos = await getAllFoosTask;
return Ok(customer);
}
Note that after Task.WhenAll completed both tasks already completed so awaiting them completes immediately.
Short answer: No.
Task.WaitAll is blocking, await returns the task as soon as it is encountered and registers the remaining part of the function and continuation.
The "bulk" waiting method you were looking for is Task.WhenAll that actually creates a new Task that finishes when all tasks that were handed to the function are done.
Like so: await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});
That is for the blocking matter.
Also your first function does not execute both functions parallel. To get this working with await you'd have to write something like this:
var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;
This will make the first example to act very similar to the Task.WhenAll method.
As an addition to what #i3arnon said. You will see that when you use await you are forced to have to declare the enclosing method as async, but with waitAll you don't. That should tell you that there is more to it than what the main answer says. Here it is:
WaitAll will block until the given tasks finish, it does not pass control back to the caller while those tasks are running. Also as mentioned, the tasks are run asynchronous to themselves, not to the caller.
Await will not block the caller thread, it will however suspend the execution of the code below it, but while the task is running, control is returned back to the caller. For the fact that control is returned back to the caller (the called method is running async), you have to mark the method as async.
Hopefully the difference is clear. Cheers
Only your second option will run them in parallel. Your first will wait on each call in sequence.
As soon as you invoke the async method it will start executing. Whether it will execute on the current thread (and thus run synchronously) or it will run async is not possible to determine.
Thus, in your first example the first method will start doing work, but then you artificially stops the flow of the code with the await. And thus the second method will not be invoked before the first is done executing.
The second example invokes both methods without stopping the flow with an await. Thus they will potentially run in parallel if the methods are asynchronous.
I may get voted as a duplicate of
wrapping-synchronous-code-into-asynchronous-call
However, My question is what if I don't care about the results of the task?
More detail: I want the task to run and whether or not it finishes, I want the task to run again in another thread.
To explain specifically, I have a service that reads a table and gets all the records that have not been processed. The task does it's business, but I don't know if there is one record or 1000 records to be processed in that instance. If it is 1000, it will take several minutes, one will take less than a second, usually the task finds nothing to do. So in that case I don't need to know the results of the previous task nor wait for it to finish.
I have read on async and if I do not consume the await result, I read that it will not continue. Is that true?
The example is:
private async Task MakeRequest()
{
mainTimer.Stop();
var task = Task.Run(() => Exec());
await task;
mainTimer.Start();
}
does this mean that the task is not ready to run again unless I have the "await task" command?
await task;
States that you want to wait for task completion and continue execute next lines.
When you run this:
Task.Run(() => Exec());
It start to execute new task immediately, doesn't matter did you use await next or not. You can run the same function in a task as many times as you want without using keyword await. But you need make sure that your function can handle concurrent execution.
If you need to get result of your task without using await, you can continue execution on the same thread on which task was started:
task.ContinueWith(task=> {});
if you don't care about the result, then use a void function:
private async void MakeRequest()
{
mainTimer.Stop();
var task = Task.Run(() => Exec());
await task;
mainTimer.Start();
}
Also, not consuming a task does not block anything, it will finish even if you don't await it.
I need to return items from partitions in service fabric and add them to a list. The results come from async methods. I try to understand what is happening to get it to run faster. Does the loop wait until await is returned for each GetItems, or does the loop continue and start a new GetItems for the next partition?
List<string> mylist = new List<string>();
foreach(var partition in partitions)
{
var int64RangePartitionInformation = p.PartitionInformation as Int64RangePartitionInformation;
if (int64RangePartitionInformation == null) continue;
var minKey = int64RangePartitionInformation.LowKey;
var assetclient = ServiceProxy.Create<IService>(serviceName, new ServicePartitionKey(minKey));
var assets = await assetclient.GetItems(CancellationToken.None);
mylist.AddRange(items)
}
The await keyword tells the compiler to refactor your method to a state machine. Once your async method is called, everything before the first await will be executed. The rest of the tasks will be registered for a delayed execution, and depending of the current configuration can be executed immediately and synchronously or on another thread.
If the awaited task is executed asynchronously, the actual method call returns, so the thread is free to do anything else, eg. refresh the UI. This refactored state machine-like method is then called again and again, polls whether the awaited task is finished. Once it is finished, the state is switched so the codes after the awaited line will be executed and so on.
So logically yes, the loop waits until the results are there, but in reality the thread is not blocked because of the state machine-like behavior mentioned above.
See a detailed explanation here.
Update:
If the results can be obtained parallelly from all partitions, do not await them one by one. Instead, use Parallel.ForEach or just populate a Task collection in your foreach loop, and finally await them in one step:
await Task.WhenAll(myTasks);
await is an "asynchronous wait". It pauses the current method and (asynchronously) waits for that operation to complete before continuing.
Note that the method is paused, not the thread. That's what makes await an "asynchronous wait" instead of a regular wait ("synchronous wait").
For more info, see my async/await intro.
Does the loop wait until await is returned for each GetItems, or does the loop continue and start a new GetItems for the next partition?
At each await, the loop is (asynchronously) waiting. So with the current code, only one call to the service is being done at a time, and the list does not have to deal with concurrent AddRange calls.
As far as I know the async await keywords work this way: when an await keyword is encountered by the compiler, it suspends the execution of the async function to the caller (in this case the dispatcher), waits for the awaitable function to complete in the background and then then returns back to the function. Am I right?
here is what I am doing:
async private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var p = await query("select* from notes", con);
}
and here is the function being called
async Task<List<notes>> query(string sqlstring, SQLiteConnection con)
{
var p = con.Query<notes>(sqlstring);
Thread.Sleep(5000);
MessageBox.Show(p[0].Data);
return p;
}
This blocks the UI thread. why is this happening shouldn't the control be transferred back to the dispatcher when it encounters the await keyword? If so why does the UI get stuck?
Your understanding of await is mostly correct, it's just incomplete. await doesn't suspend execution of the current method immediately. First, the value to be awaited needs to be resolved to a value. Typically you'll have some sort of method that creates a Task. That task will be created synchronously, and then after creating that task, execution of the current method will end, and a continuation will be applied to that task that executes the remainder of the method.
For an async method everything before the first await will be performed synchronously by the caller. It is when the first await (or the end of the method, or an exception that isn't caught by the method) that causes the method to return an actual Task.
Your query method should be able to create the Task that represents the completion of the operation very quickly and then return, so that the caller can await that Task. But it doesn't, it spends over 5 seconds creating the task that represents when it will finish, and when it ends up giving that task to its caller that Task has already finished.
This means that Button_Tap can't yield to its caller (which is the UI's message loop) until after query has finished its 5 seconds of task creation.
All of this means that for Button_Tap to be asynchronous query needs to be asynchronous, and not asynchronous in that it uses the async keyword, but asynchronous in the sense that the method returns almost immediately when called, and that it performs its work after yielding control back to the caller.
As to how to make the method asynchronous, that'll depend. For IO, such as querying a database, what you really want is to have the query provider itself provide inherently asynchronous support. You want to have a query method that returns a Task that you can await, rather than synchronously returning its results. If you have no other choice, then as a last resort you can use Task.Run to perform the query in a non-UI thread and then await that.
As for the Thread.Sleep, that is also synchronously blocking the thread. You need to asynchronously do something after a set period of time instead (if you really do need the delay). You can use Task.Delay for that.
async Task<List<notes>> query(string sqlstring, SQLiteConnection con)
{
var p = await con.QueryAsync<notes>(sqlstring);
//Or, if there is no asynchronous query method
//var p = await Task.Run(() => con.Query<notes>(sqlstring));
await Task.Delay(5000);
MessageBox.Show(p[0].Data);
return p;
}
On a side note, you really shouldn't be trying to re-use your database connections like this. They aren't designed to be used concurrently, for starters. Really they're inherently designed to perform just a single operation. You should be creating your connection right when you need it, and cleaning it up as soon as that one operation has been performed.
I read in the book about the differences of the below.
private async Task GetDataAsync() {
var task1 = ReadDataFromIOAsync();
var task2 = ReadDataFromIOAsync();
// Here we can do more processing
// that doesn't need the data from the previous calls.
// Now we need the data so we have to wait
await Task.WhenAll(task1, task2);
// Now we have data to show.
lblResult.Content = task1.Result;
lblResult2.Content = task2.Result;
}
private async Task GetDataAsync() {
var task1 = ReadDataFromIOAsync();
var task2 = ReadDataFromIOAsync();
lblResult.Content = await task1;
lblResult2.Content = await task2;
}
I understood whats happening in the first method's await statement. But for the second one, though I understood the logic I couldn't understand the pitfall of the second implementation compared to first. In the book, they mentioned that compiler rewrites the method twice. What I understood is because of the two await calls, there could be a time delay more than the first one as we separately call the await for each task here. Can someone explain me in a better way?
I don't know what point your book was trying to make but I agree with your initial guess at it's interoperation.
Potentially the issue is there could be a period of time where lblResult shows new data and lblResult2 shows old data if task2 takes longer than task1 to process. In the first method you wait till both tasks finish then update both labels at the same time (and when you exit your method both get repainted on the screen a the same time). In the second method you update the first label then you give the message loop a opportunity to repaint the screen then some time later you update the 2nd label and have that value get updated on the screen.
I guess you would have a slightly more complex state machine for the 2nd example too but the overhead of that is negligible, I am confident the book was trying to point out the issue you and I both came up with.
Essentially what the first method is doing is this:
Start task1
Start task2
Asynchronously wait for task1 and task2 to complete
The second implementation does this:
Start task1
Start task2
Asynchronously wait for task1 to complete.
Once task1 is complete, resume execution and then asynchronously wait for task2 to complete.
So with the second approach you are individually awaiting the results of each task rather than waiting for both tasks to complete. In the case where task1 completes before task2, the code will resume execution and then return straight away, that will result in an extra context switch which may take extra time. Also for the case of multiple awaits the compiler may end up generating a more complex state machine, but the effect of that should be negligible.
In either case you are not using the result until both tasks are complete so the behavior of the application shouldn't be too different.