difference between await Task(ReadFromIO) and await Task.WhenAll(task1,task2); - c#

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.

Related

Proper way to "fire and forget" async Tasks or run it in background

I need to run some async tasks which result I never gonna use anywhere and I don't care when it will be finished.
For example, I might need my Discord client to respond on some command like this:
// .command
await StartLongAsyncTaskThatMayTakeForeverToCompleteAndSay("I'm late");
await Context.Message.ReplyAsync("Immediately say hi"));
// => "Immediately say hi"
// *few seconds later*
// => "I'm late"
Should I do it with: await StartLongAsyncTask().ConfigureAwait(false); or _ = StartLongAsyncTask(); or should I use Task.Run(() => {} );, and what is the difference?
It hugely depends on what StartLongAsyncTaskThatMayTakeForeverToCompleteAndSay is and the context, for example in some cases assigning invocation result to a task variable and awaiting it after the second call can be ok:
var task = StartLongAsyncTaskThatMayTakeForeverToCompleteAndSay("I'm late");
await Context.Message.ReplyAsync("Immediately say hi"));
await task;
Or just:
await Task.WhenAll(StartLongAsyncTaskThatMayTakeForeverToCompleteAndSay("I'm late"),
Context.Message.ReplyAsync("Immediately say hi")));
For differences between the two - see Why should I prefer single 'await Task.WhenAll' over multiple awaits?.
Well you definitely don't want to await your long running task and then reply after, you seem to want to reply right away and let the long running task run its course:
// .command
_ = StartLongAsyncTaskThatMayTakeForeverToCompleteAndSay("I'm late");
await Context.Message.ReplyAsync("Immediately say hi"));
// => "Immediately say hi"
// *few seconds later*
// => "I'm late"
and what is the difference
The difference between the last 2 options on your list (the first one I should think is obvious) is that the Task.Run version runs the async function on the thread pool, which you should never manually do for any sort of well behaved API, while simply calling the task runs it (or at least starts it) on your own thread (which is perfectly fine for I/O bound operations).

Run async operation in parallel without Task.WhenAll

I need to run three async I/O operations in parallel, particularly they are the database calls. So, I write the following code:
// I need to know whether these tasks started running here
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
// await the results
var task1Result = await task1;
var task2Result = await task2;
var task3Result = await task3;
The GetThingOneAsync(), GetThingTwoAsync(), GetThingThreeAsync() methods are pretty much the similar to each other except that they have different return types(Task<string>, Task<int>, Task<IEnumerable<int>>). The example of one of the database calls is the following:
public async Task<IEnumerable<int>> GetThingOneAsync(string code)
{
return await db.DrType.Where(t => t.Code == code).Select(t => t.IdType).ToListAsync();
}
In debug mode I can see that var task1 = _repo.GetThingOneAsync(); started to run GetThingOneAsync() async method (the same with other two tasks).
My colleagues say that _repo.GetThingOneAsync() does not start the async operation. They say that the operation started when we reach await (that statement seems to be wrong for me).
So, they suggest to fix my code to the following:
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
await Task.WhenAll(task1, task2, task3);
// then get the result of each task through `Result` property.
In my opinion, it's the same as I wrote in the very beginning of the question except that Task.WhenAll waits for later tasks to finish if an earlier task faults (this is Servy's comment from this question)
I know that my question is kind of duplicate but I want to know whether I'm doing things right or wrong.
My colleagues say that _repo.GetThingOneAsync() does not start the async operation. They say that the operation started when we reach await (that statement seems to be wrong for me).
They're wrong. The operation starts when the method is called.
This is easy to prove by starting an operation that has some observable side effect (like writing to a database). Call the method and then block the application, e.g., with Console.ReadKey(). You will then see the operation complete (in the database) without an await.
The remainder of the question is all about stylistic preference. There's a slight semantic difference between these options, but usually it's not important.
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
// await the results
var task1Result = await task1;
var task2Result = await task2;
var task3Result = await task3;
The code above will await (asynchronously wait) for each task to complete, one at a time. If all three complete successfully, then this code is equivalent to the Task.WhenAll approach. The difference is that if task1 or task2 have an exception, then task3 is never awaited.
This is my personal favorite:
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
await Task.WhenAll(task1, task2, task3);
var task1Result = await task1;
var task2Result = await task2;
var task3Result = await task3;
I like the Task.WhenAll because it's explicit. Reading the code, it's clear that it's doing asynchronous concurrency because there's a Task.WhenAll right there.
I like using await instead of Result because it's more resilient to code changes. In particular, if someone who doesn't like Task.WhenAll comes along and removes it, you still end up awaiting those tasks instead of using Result, which can cause deadlocks and wrap exceptions in AggregateException. The only reason Result works after Task.WhenAll is because those tasks have already been completed and their exceptions have already been observed.
But this is largely opinion.
I agree with #MickyD, the tasks have been created on the initial call. The two calls are similar in effect.
A few nuances though. When you call GetThingOneAsync method, it executes up until the point where it reaches an await statement; that is when it returns the Task. If the Async method never does an await then it exits and returns an already-completed Task. So if these were compute-intensive routines (doesn't look like it) then you would not be achieving any parallelism. You would need to use Task.Run to achieve simultaneous execution. Another point is that if you use await from the UI thread then all of the execution will be on the UI thread -- just scheduled at different times. This is somewhat OK if the Task is doing IO because it will block for the read/write. However it can start to add up so if you are going to do anything substantial then you should put it on the thread pool (I.e. with Task.Run).
As for the comment from your colleagues, as I said, the task1,2,3 do start running before the awaits. But when you hit the await, the method that you are currently executing will suspend and return a Task. So it is somewhat correct that it is the await that creates the Task -- just that the task you are thinking about in your question (task1,2,3) is the one created when GetThingXxxAsync hits an await, not the one created when your main routine awaits task1,2,3.

How to make two Tasks run with an even distribution of cpu time

They start out even, but eventually the processTasks never gets hits.
Originally I had this as two threads when the tasks were simple. Someone suggested async/await tasks and being new to c# I had no reason to doubt them.
Task monitorTasks= new Task (monitor.start );
Task processTasks= new Task( () => processor.process(ref param, param2) );
monitorTasks.Start();
processTasks.Start();
await processTasks;
Have I executed this wrong? Is my problem inevitable while running two tasks? Should they be threads? How to avoid.
edit
To clarify. The tasks are never intended to end. They will always be processing and monitoring while triggering events that notify watchers of monitor outputs or processor outputs.
If you await on a Task.WhenAll then it will wait until all tasks have been processed
await Task.WhenAll(monitorTasks, processTasks)
https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.whenall(v=vs.110).aspx
Task.WaitAll blocks the current thread until everything has completed.
Task.WhenAll returns a task which represents the action of waiting until everything has completed.
Task.WhenAll Method
Creates a task that will complete when all of the Task objects in an
enumerable collection have completed.
Task.WaitAll Method
Waits for all of the provided Task objects to complete execution.
If you want to block wait on started tasks (which is seemingly what you want)
Task monitorTasks= new Task (monitor.start );
Task processTasks= new Task( () => processor.process(ref param, param2) );
monitorTasks.Start();
processTasks.Start();
Task.WaitAll(new Task[]{monitorTasks,processTasks})
If you are using async await, see Asynchronous programming with async and await
Then you could do something like this
var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();
await Task.WhenAll(task1, task2);
I couldn't get tasks to run evenly.
The monitor task was getting constantly flooded whereas the processor task was getting tasks less frequently, which is when I suspect the monitor task took over.
Since no one could help me,
My solution was to turn them back into threads and set the priority of the threads.Lower than normal for the monitor task, and higher than normal for the processor task.
This seems to have solved my problem.

Wrapping an synchronus method to run asynchronously

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.

Understanding acync and await in C#

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);

Categories