I've read that Task.Delay() is advised to be awaited not to block the calling thread (as oposed to Task.Delay().Wait() and Thread.Sleep()). But as I learned more about async/await I got a feeling that all it does is shifting the awaitable task for an execution on another thread.
So, did I understand it correctly: await Task.Delay() does not block the calling thread, however it blocks SOME thread, where the awaited task gets shifted to?
If that statement IS TRUE, then could you advice me on a method that asks a task to wait for a while WITHOUT blocking any thread during the wait?
however it blocks SOME thread, where the awaited task gets shifted to?
It depends on what you mean by "block". It doesn't cause any thread to go to sleep for 1 second, or (worse) spin wait for the delay to complete. Instead, it effectively schedules a timer to fire in 1 second, and then executes the continuation that will have been registered due to the await.
At a somewhat simplified level, await just translates to:
Call GetAwaiter on the awaitable, to get an awaiter
Check whether the awaiter has already completed - if so, just continue
Otherwise, schedule a continuation with the awaiter, and return
When the awaiter completes, the continuation is called and the async method continues
The clever bit is the way that the compiler saves state and manages the continuation so that it continues from the end of the await expression.
So as I get it, the the thread where the awaited Delay() task gets sent to >can be used to process other tasks, while Delay() is under way? – cubrman Aug >15 at 10:19
No, you cannot do other things while you await for task.delay. The instruction below won't get executed, but the thread won't be blocked too! This means interface processing will still be working, you would be able for example move the mouse , click buttons etc.
Related
I have an async method that get data from a database:
private async Task getDataAsync()
{
await getDataFromDatabaseAsync();
}
I have a contructor that uses this method, in this way:
public MyViewModel()
{
Task.WhenAll(getDataAsync());
//getDataAsync().ConfigureAwait(false);
//next line of code
}
The only way that I get to avoid the applications isn't blocked is using one the two options, both seems to work fine. I can use WhenAll or I can use ConfigureAwait(false).
Another options it is calling the method getDataASync() inside a task, but I guess it is a worse option becase it takes more resources.
So I would like to know which is the differences between WhenAll and ConfigureAwait.
When I use WhenAll in this way, the line of code "next line of code" is run after the async method is finisihed or it will run before finish?
Thanks.
There is a common misconception that when you make a method async, it will be actually executed asynchronously (i.e. on a separate thread). That is not the case: async and await are a means to synchronize already asnychronous code. If you have nothing that is executed on a separate thread, your async code will run fully synchronously to the end.
Since getDataAsync is executed on the same thread as the MyViewModel constructor, you can run into a deadlock, since the thread waits for itself. When you use ConfigureAwait, you can avoid this situation.
Whether you actually should do that is a different question. What you are actually doing with ConfigureAwait is to start the task and to allow the await to continue on a separate context (which can be on a separate thread). Apart from the fact that you are not even using await here, continuation in a different context can become a problem when you want to execute UI operations after the await.
If you want to be sure that you can wait for getDataAsync in your constructor, you can use Task.Run to force execution in the thread pool:
var getDataTask = Task.Run((Func<Task>)getDataAsync);
//Do something else
getDataTask.Wait();
Everything you execute between Task.Run and the Wait() can run during the execution of getDataAsync. Whether parallelism is actually worth it here depends on what else you do until the Wait().
What you are doing in the MyViewModel constructor is to finally synchronize all asynchronous operations and make the execution of the constructor synchronous. If you want to run that operation asynchronously, you would need to start another task to do it. So you should be really sure that beyond that point async is not required anymore. If it is, run the initialization on another async method, await getDataAsync() there and synchronize somewhere up the call chain.
Whilst I've been using async code in .NET for a while, I've only recently started to research it and understand what's going on. I've just been going through my code and trying to alter it so if a task can be done in parallel to some work, then it is. So for example:
var user = await _userRepo.GetByUsername(User.Identity.Name);
//Some minor work that doesn't rely on the user object
user = await _userRepo.UpdateLastAccessed(user, DateTime.Now);
return user;
Now becomes:
var userTask = _userRepo.GetByUsername(User.Identity.Name);
//Some work that doesn't rely on the user object
user = await _userRepo.UpdateLastAccessed(userTask.Result, DateTime.Now);
return user;
My understand is that the user object is now being fetched from the database WHILST some unrelated work is going on. However, things I've seen posted imply that result should be used rarely and await is preferred but I don't understand why I'd want to wait for my user object to be fetched if I can be performing some other independant logic at the same time?
Let's make sure to not bury the lede here:
So for example: [some correct code] becomes [some incorrect code]
NEVER NEVER NEVER DO THIS.
Your instinct that you can restructure your control flow to improve performance is excellent and correct. Using Result to do so is WRONG WRONG WRONG.
The correct way to rewrite your code is
var userTask = _userRepo.GetByUsername(User.Identity.Name);
//Some work that doesn't rely on the user object
user = await _userRepo.UpdateLastAccessed(await userTask, DateTime.Now);
return user;
Remember, await does not make a call asynchronous. Await simply means "if the result of this task is not yet available, go do something else and come back here after it is available". The call is already asynchronous: it returns a task.
People seem to think that await has the semantics of a co-call; it does not. Rather, await is the extract operation on the task comonad; it is an operator on tasks, not call expressions. You normally see it on method calls simply because it is a common pattern to abstract away an async operation as a method. The returned task is the thing that is awaited, not the call.
However, things I've seen posted imply that result should be used rarely and await is preferred but I don't understand why I'd want to wait for my user object to be fetched if I can be performing some other independent logic at the same time?
Why do you believe that using Result will allow you to perform other independent logic at the same time??? Result prevents you from doing exactly that. Result is a synchronous wait. Your thread cannot be doing any other work while it is synchronously waiting for the task to complete. Use an asynchronous wait to improve efficiency. Remember, await simply means "this workflow cannot progress further until this task is completed, so if it is not complete, find more work to do and come back later". A too-early await can, as you note, make for an inefficient workflow because sometimes the workflow can progress even if the task is not complete.
By all means, move around where the awaits happen to improve efficiency of your workflow, but never never never change them into Result. You have some deep misunderstanding of how asynchronous workflows work if you believe that using Result will ever improve efficiency of parallelism in the workflow. Examine your beliefs and see if you can figure out which one is giving you this incorrect intuition.
The reason why you must never use Result like this is not just because it is inefficient to synchronously wait when you have an asynchronous workflow underway. It will eventually hang your process. Consider the following workflow:
task1 represents a job that will be scheduled to execute on this thread in the future and produce a result.
asynchronous function Foo awaits task1.
task1 is not yet complete, so Foo returns, allowing this thread to run more work. Foo returns a task representing its workflow, and signs up completing that task as the completion of task1.
The thread is now free to do work in the future, including task1.
task1 completes, triggering the execution of the completion of the workflow of Foo, and eventually completing the task representing the workflow of Foo.
Now suppose Foo instead fetches Result of task1. What happens? Foo synchronously waits for task1 to complete, which is waiting for the current thread to become available, which never happens because we're in a synchronous wait. Calling Result causes a thread to deadlock with itself if the task is somehow affinitized to the current thread. You can now make deadlocks involving no locks and only one thread! Don't do this.
Async await does not mean that several threads will be running your code.
However, it will lower the time your thread will be waiting idly for processes to finish, thus finishing earlier.
Whenever the thread normally would have to wait idly for something to finish, like waiting for a web page to download, a database query to finish, a disk write to finish, the async-await thread will not be waiting idly until the data is written / fetched, but looks around if it can do other things instead, and come back later after the awaitable task is finished.
This has been described with a cook analogy in this inverview with Eric Lippert. Search somewhere in the middle for async await.
Eric Lippert compares async-await with one(!) cook who has to make breakfast. After he starts toasting the bread he could wait idly until the bread is toasted before putting on the kettle for tea, wait until the water boils before putting the tea leaves in the teapot, etc.
An async-await cook, wouldn't wait for the toasted bread, but put on the kettle, and while the water is heating up he would put the tea leaves in the teapot.
Whenever the cook has to wait idly for something, he looks around to see if he can do something else instead.
A thread in an async function will do something similar. Because the function is async, you know there is somewhere an await in the function. In fact, if you forget to program the await, your compiler will warn you.
When your thread meets the await, it goes up its call stack to see if it can do something else, until it sees an await, goes up the call stack again, etc. Once everyone is waiting, he goes down the call stack and starts waiting idly until the first awaitable process is finished.
After the awaitable process is finished the thread will continue processing the statements after the await until he sees an await again.
It might be that another thread will continue processing the statements that come after the await (you can see this in the debugger by checking the thread ID). However this other thread has the context of the original thread, so it can act as if it was the original thread. No need for mutexes, semaphores, IsInvokeRequired (in winforms) etc. For you it seems as if there is one thread.
Sometimes your cook has to do something that takes up some time without idly waiting, like slicing tomatoes. In that case it might be wise to hire a different cook and order him to do the slicing. In the mean time your cook can continue with the eggs that just finished boiling and needed peeling.
In computer terms this would be if you had some big calculations without waiting for other processes. Note the difference with for instance writing data to disk. Once your thread has ordered that the data needs to be written to disk, it normally would wait idly until the data has been written. This is not the case when doing big calculations.
You can hire the extra cook using Task.Run
async Task<DateTime> CalculateSunSet()
{
// start fetching sunset data. however don't wait for the result yet
// you've got better things to do:
Task<SunsetData> taskFetchData = FetchSunsetData();
// because you are not awaiting your thread will do the following:
Location location = FetchLocation();
// now you need the sunset data, start awaiting for the Task:
SunsetData sunsetData = await taskFetchData;
// some big calculations are needed, that take 33 seconds,
// you want to keep your caller responsive, so start a Task
// this Task will be run by a different thread:
Task<DateTime> taskBigCalculations = Taks.Run( () => BigCalculations(sunsetData, location);
// again no await: you are still free to do other things
...
// before returning you need the result of the big calculations.
// wait until big calculations are finished, keep caller responsive:
DateTime result = await taskBigCalculations;
return result;
}
In your case, you can use:
user = await _userRepo.UpdateLastAccessed(await userTask, DateTime.Now);
or perhaps more clearly:
var user = await _userRepo.GetByUsername(User.Identity.Name);
//Some work that doesn't rely on the user object
user = await _userRepo.UpdateLastAccessed(user, DateTime.Now);
The only time you should touch .Result is when you know the task has been completed. This can be useful in some scenarios where you are trying to avoid creating an async state machine and you think there's a good chance that the task has completed synchronously (perhaps using a local function for the async case), or if you're using callbacks rather than async/await, and you're inside the callback.
As an example of avoiding a state machine:
ValueTask<int> FetchAndProcess(SomeArgs args) {
async ValueTask<int> Awaited(ValueTask<int> task) => SomeOtherProcessing(await task);
var task = GetAsyncData(args);
if (!task.IsCompletedSuccessfully) return Awaited(task);
return new ValueTask<int>(SomeOtherProcessing(task.Result));
}
The point here is that if GetAsyncData returns a synchronously completed result, we completely avoid all the async machinery.
Have you considered this version?
var userTask = _userRepo.GetByUsername(User.Identity.Name);
//Some work that doesn't rely on the user object
user = await _userRepo.UpdateLastAccessed(await userTask, DateTime.Now);
return user;
This will execute the "work" while the user is retrieved, but it also has all the advantages of await that are described in Await on a completed task same as task.Result?
As suggested you can also use a more explicit version to be able to inspect the result of the call in the debugger.
var userTask = _userRepo.GetByUsername(User.Identity.Name);
//Some work that doesn't rely on the user object
user = await userTask;
user = await _userRepo.UpdateLastAccessed(user, DateTime.Now);
return user;
What is the difference when using await on multiple await task vs waiting on all the tasks to finish. My under standing is the scenario 2 is better in terms of performance because both asyncTask1 and asyncTask2 are preformed in parallel.
scenario 1 :
async Task Task()
{
await asyncTask1();
await asyncTask2();
}
scenario 2 :
async Task Task()
{
t1 = asyncTask1();
t2 = asyncTask2();
await Task.WhenAll(createWorkflowtask, getTaskWorkflowTask);
}
In scenario 1, tasks are run sequentially (asyncTask1 must complete before asyncTask2 starts) while in scenario 2 the two tasks can run in parallel.
You wrote: "... because both asyncTask1 and asyncTask2 are preformed in parallel."
No they are not!
Addition: Below I wrote that everything in async-await is performed by one thread. Schneider commented correctly that in async-await multiple threads can be involved. See the addition at the end.
An article that helped me a lot to understand how async-await works was this interview with Eric-Lippert who compared async/await with a cook making dinner. (Somewhere half-way, search for async-await).
Eric Lippert explains that if a cook starts doing something and finds after a while that he has nothing else to do but wait for a process to finish, this cook looks around to see if he can do something else instead of waiting.
When using async/await, there is still one thread involved. This thread can do only one thing at a time. While the thread is busy doing Task1, it can't execute Task2. Only if it finds an await in Task1, it will start executing statements from Task2. In your scenario 2 the tasks are not executed in parallel.
However there is a difference between the scenarios. In scenario 1 the first statement of task2 will not be executed before task1 completely finishes. Scenario 2 will start executing the first statements of task2 as soon as task1 encounters an await.
If you really want task2 to do something while task1 is also doing something, you'll have to start doing task2 in a separate thread. The easy method to do this in your scenario would be:
var task1 = Task.Run( () => asyncTask1())
// this statement is executed while task1 begins executing on a different thread.
// hence this thread is free to do other things, like performing statements
// from task2:
var task2 = asyncTask();
// the following statement will only be executed if task2 encounters an await
DoSomethingElse();
// when we need results from both task1 and task2:
await Task.WhenAll(new Task[] {task1, task2});
So usually, it is best only to await for a task to finish if you need the result of this task. As long as you can do other things, do these other things, they will be executed as soon as the other task starts awaiting until you start awaiting, in which case your caller will start doing things until his await etc.
The advantage of this method above doing things in parallel are manyfold:
Everything is performed by one thread: no need of mutexes, no chance of deadlock, starvation, etc
Your code looks quite sequential. Compare this with code that uses Task.ContinueWith and similar statements
There is no overhead of starting a separate thread / running a thread from the thread pool
Addition: Schneider's comment below about several threads is correct.
Some testing showed me that the thread ID of the current thread in the awaitable tasks is different than the thread ID of the calling thread.
For newbees to async-await it is important to understand that although various threads are involved, async-await does NOT mean that the tasks are performed in parallel. If you want parallelism you specifically have to say that the task must be run in parallel.
It seems that the cook in Eric Lippert's analogy is in fact a team of cooks, who constantly look around to see if they can help some of the other cooks instead of waiting for their tasks to finish. And indeed if cook Albert sees an await and starts doing something else, cook Bernard might finish the task of cook Albert.
In the first scenario you launch a task and then wait until is completed, then pass to the second one and wait until finish before exit from the method.
In the second scenario you launch the two task in parallel and then wait until tgey are completed when you call Task.WhenAll
Using Task.WhenAll
You cannot use methods with return types unless all of return types are the same and using generic version of WhenAll method
You don't have control over sequences that methods executed because these methods is executing in parallel
Unhandled exception in one method doesn't break the execution of other methods(because of parallel nature)
From MSDN
If any of the supplied tasks completes in a faulted state, the returned task will also complete in a TaskStatus.Faulted state, where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.
Using await on multiple methods
You have control over sequences that functions called
You can use different return types and use that return types on next steps
Unhandled exception in one method will break the execution of other methods
Initially I thought that all continuations are executed on the threadpool (given a default synchronization context). This however doesn't seem to be the case when I use a TaskCompletionSource.
My code looks something like this:
Task<int> Foo() {
_tcs = new TaskCompletionSource<int>();
return _tcs.Task;
}
async void Bar() {
Console.WriteLine(Thread.Current.ManagedThreadId);
Console.WriteLine($"{Thread.Current.ManagedThreadId} - {await Foo()}");
}
Bar gets called on a specific thread and the TaskCompletionSource stays unset for some time, meaning the returned tasks IsComplete = false. Then after some time, the same thread would proceed to call _tcs.SetResult(x), which by my understanding should run the continuation on the threadpool.
But what I observed in my application is that the thread running the continuation is in fact still the same thread, as if the continuation was invoked synchronously right as SetResult is called.
I even tried setting a breakpoint on the SetResult and stepping over it (and having a breakpoint in the continuation), which in turn actually goes on to call the continuation synchronously.
When exactly does SetResult() immediately call the continuation synchronously?
Initially I thought that all continuations are executed on the threadpool (given a default synchronization context). This however doesn't seem to be the case when I use a TaskCompletionSource.
Actually, when using await, most continuations are executed synchronously.
Marc's answer is great; I just wanted to go into a bit more detail...
TaskCompletionSource<T> by default will operate synchronously when Set* is called. Set* will complete the task and issue the continuations in a single method call. (This means that calling Set* while holding a lock is a recipe for deadlocks.)
I use the weird phrase "issue the continuations" there because it may or may not actually execute them; more on that later.
The TaskCreationOptions.RunContinuationsAsynchronously flag will tell TaskCompletionSource<T> to issue the continuations asynchronously. This breaks apart the completing of the task (which is still done immediately by Set*) from the issuing of the continuations (which is only triggered by the Set* call). So with RunContinuationsAsynchronously, a Set* call will only complete the task; it will not execute the continuations synchronously. (This means that calling Set* while holding a lock is safe.)
But back to the default case, which issues the continuations synchronously.
Each continuation also has a flag; by default a continuation is executed asynchronously, but it can be made synchronous by TaskContinuationOptions.ExecuteSynchronously. (Note that await does use this flag - link is to my blog; technically this is an implementation detail and not officially documented).
However, even if ExecuteSynchronously is specified, there are a number of situations where the continuation is not executed synchronously:
If there is a TaskScheduler associated with the continuation, that scheduler is given the option of rejecting the current thread, in which case the task is queued to that TaskScheduler instead of executing synchronously.
If the current thread is being aborted, then the task is queued elsewhere.
If the current thread's stack is too deep, then the task is queued elsewhere. (This is only a heuristic, and not guaranteed to avoid StackOverflowException).
That's quite a few conditions, but with your simple Console app test, they're all met:
TaskCompletionSource<T> does not specify RunContinuationsAsynchronously.
The continuation (await) does specify ExecuteSynchronously.
The continuation does not have a TaskScheduler specified.
The target thread is able to execute the continuation (not being aborted; stack is ok).
As a general rule, I would say any usage of TaskCompletionSource<T> should specify TaskCreationOptions.RunContinuationsAsynchronously. Personally, I think the semantics are more appropriate and less surprising with that flag.
SetResult usually runs continuations from TCS synchronously. There main exception to this is if you explicitly pass in the TaskContinuationOptions.RunContinuationsAsynchronously flag when creating the TCS (new in .NET 4.6). The other scenario when it runs things asynchronously is if it thinks the current thread is doomed.
This is quite important, because if you're not careful you can end up having calling code take control of a thread that was meant to be doing other work (like: dealing with socket IO).
When we use await in the code, generally the awaiters capture the context and use that as callback when the awaited task completed successfully. But, since await is generally a No-Op (No Operation), does it make the underlying thread not being reusable until execution of the awaited task completes?
For Example:
public async Task MethodAAsync()
{
// Execute some logic
var test = await MethodB();
// Execute remaining logic
}
Here, since I need the result back to proceed further, I need to await on that. But, since we are awaiting, does it block the underlying thread resulting thread not being used to execute any tasks?
But, since await is generally a No.Op(No Operation), does it make the
underlying thread not being reusable until execution of awaited task
completes?
I'm not sure where you got this information from, but await is certainly not a No-Op. Calling await on a Task, for example, will invoke a logical call to Task.GetAwaiter, where the TaskAwaiter has to implement INotifyCompletion or ICriticalNotifyCompletion interface, which tells the compiler how to invoke the continuation (everything after the first await).
The complete structure of async-await transforms your call to a state-machine such that when the state-machine hits the first await, it will first check to see if the called method completed, and if not will register the continuation and return from that method call. Later, once that method completes, it will re-enter the state-machine in order to complete the method. And that is logically how you see the line after await being hit.
But, since we are awaiting, does it block the underlying thread
resulting thread not being used to execute any tasks?
No, creating an entire mechanism only to block the calling thread would be useless. async-await allow you to actually yield the calling thread back to the caller which allows him to continue execution on that same thread, while the runtime takes care of queuing and invoking the completion.
In short, no, it doesn't block your thread.
More info: http://blog.stephencleary.com/2013/11/there-is-no-thread.html
The thread has a local queue of Tasks. Once it hits an await it will pick up another Task from it's queue (assuming all methods up it's stack are awaited). If the queue is empty, it will try to get a Task from the global queue, and if it's empty too - the thread will try to get a Task from another thread's own local queue. In a simple program, where all threads might get "out of Tasks" - the thread will remain idle until one of the Tasks returns.