I've read here that :
Await examines that awaitable to see if it has already completed; if
the awaitable has already completed, then the method just continues
running (synchronously, just like a regular method).
What ?
Of course it won't be completed because it hasn't even started !
example :
public async Task DoSomethingAsync()
{
await DoSomething();
}
Here await examines the awaitable to see if it has already completed
(according to the article) , but it (DoSomething) haven't event started yet ! , so the result will always be false
It would make sence if the article was to say :
Await examines that awaitable to see if it has already completed
within x ms; (timeout)
I probably missing something here..
Consider this example:
public async Task<UserProfile> GetProfileAsync(Guid userId)
{
// First check the cache
UserProfile cached;
if (profileCache.TryGetValue(userId, out cached))
{
return cached;
}
// Nope, we'll have to ask a web service to load it...
UserProfile profile = await webService.FetchProfileAsync(userId);
profileCache[userId] = profile;
return profile;
}
Now imagine calling that within another async method:
public async Task<...> DoSomething(Guid userId)
{
// First get the profile...
UserProfile profile = await GetProfileAsync(userId);
// Now do something more useful with it...
}
It's entirely possible that the task returned by GetProfileAsync will already have completed by the time the method returns - because of the cache. Or you could be awaiting something other than the result of an async method, of course.
So no, your claim that the awaitable won't have completed by the time you await it isn't true.
There are other reasons, too. Consider this code:
public async Task<...> DoTwoThings()
{
// Start both tasks...
var firstTask = DoSomethingAsync();
var secondTask = DoSomethingElseAsync();
var firstResult = await firstTask;
var secondResult = await secondTask;
// Do something with firstResult and secondResult
}
It's possible that the second task will complete before the first one - in which case by the time you await the second task, it will have completed and you can just keep going.
await can take any Task or Task<T>, including completed tasks.
In your example, the inner DoSomething() method (that should rather be named DoSomethingAsync(), and its caller DoSomethingElseAsync()) returns a Task (or a Task<T>). That task can be a completed task fetched from somewhere else, the method is not required to start its own task.
Related
While messing around with SignalR I found a behaviour that confuse me.
Calling StartCountDown from a client then make a call to Join behaves like
wait 10 seconds
Call clients CountDownStarted
Then call PlayerJoined
What I expected.
Call start CountDown, return
immediately call PlayerJoined
After 10 seconds complete CountDownStarted.
public class AHub : Hub
{
public async Task Join(string player)
{
await Clients.All.PlayerJoined(player);
}
public async Task StartCountDown()
{
await Task.Delay(10000);
await Clients.All.CountDownStarted();
}
}
This is from a SignalR Hub
This is a common misconception about the async and await pattern. Awaiting something does actually await the completion of the task.
If you want to run the task unobserved (or colloquially known as fire and forget), you could do thus
// task gets started hot and unobserved, remove the warning with a discard
_ = StartCountDownAsync();
Note : An exception that's raised in a method that returns a Task or Task<TResult> is stored in the returned task. If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown.
As a best practice, you should always await the call.
Though, you have other options. Which is to start a task, complete other tasks, and then await the completion of the original
Given
public async Task SomeTask1() { }
public async Task SomeTask2() { }
public async Task SlowApiAsync() { }
You might want
var slowApiTask = SlowApiAsync();
await SomeTask1();
await SomeTask2();
await slowApiTask;
Or if you want to run all the tasks concurrently (and yet await them all)
var slowApiTask = SlowApiAsync();
var task1 = SomeTask1();
var task2 = SomeTask2();
await Task.WhenAll(slowApiTask,task1,task2)
This question already has answers here:
What does await do in this function?
(3 answers)
Closed 2 years ago.
What is the purpose of the await keyword in the following code?
Does it create new thread for PostAsync function and then wait until that thread completes to return the await result?
Or does it not wait?
In the code below, would it be possible for Pins.Add function to execute before the firebase.PostAsync call is completed?
public async Task AddData(int id, string description, DateTime postdate, string usernames)
{
await firebase
.Child("Entries")
.PostAsync(new Entry() { id = id, description = description, postdate = postdate, username = username });
}
public MapPage()
{
AddData(1, result, DateTime.Now, deviceId);
customMap.Pins.Add(new CustomPin
{
..//
});
}
I cannot remove the async keyword from definition from AddData, so if this is incorrect, how would I fix this? The other option is to remove both keywords, would this still work with FireBase PostAsync call?
public void AddData(int id, string description, DateTime postdate, string usernames)
{
firebase
.Child("Entries")
.PostAsync(new Entry() { id = id, description = description, postdate = postdate, username = username });
}
What is the purpose of the await keyword in the following code?
It conceptually pauses the execution of the current method, until the awaited-thing completes.
Does it create new thread for PostAsync function and then wait until that thread completes to return the await result?
No, await itself does not create any new threads, and it does not really wait. It just looks like it does.
Or does it not wait?
Yes, it does not cause the thread to wait in the 'does it block?' sense. However, execution of the rest of 'AddData' method is paused. Yes, I've said 'AddData'. Execution of 'MapPage' is not affected. That may be a bug in your code (explained below).
In the code below, would it be possible for Pins.Add function to execute before the firebase.PostAsync call is completed?
Yes it certainly is.
I cannot remove the async keyword from definition from AddData, so if this is incorrect, how would I fix this?
AddData needs to be marked as async and needs to return a Task because its implementation uses await keyword. Using the await keyword is not a must. You may handle the Task returned by PostAsync in some other way. But when using await keyword, you MUST be in async-marked-Task-returning method.
If by "fix this" you mean you're concerned that Pins.Add should not execute before PostAsync completes, then you have to propagate the async-await pattern and make the MapPage "wait" for the result of AddData:
public async Task MapPage()
{
await AddData(1, result, DateTime.Now, deviceId);
customMap.Pins.Add(new CustomPin
{
..//
});
}
That's the bare minimum to answer your questions, but I think you may find a few more notes helpful.
As you may have noticed, if you HAVE to await the AddData, then it may mean that the caller of MapPage will have to await the MapPage as well. And so on. Maybe somewhere up above the call stack you will have the freedom to not await or to work around it in some way. But in general, it propagates up the call chain. Like an exception. It's not one of course, but think of it: if your current method has to "wait for something" then the method above.. ..probably has to be able to as well. At least if it wants to know the result of your current method - it has to wait until your current method actually produces that result, right? So it has to propagate as long as the result is important to the caller.
To explain how that happens: await splits the code in half, and POSTPONES the other half.
public async Task AddData(...)
{
await firebase
....
.PostAsync(...);
int x = 5;
}
becomes something like:
public async Task AddData(...)
{
Task tmp = firebase
....
.PostAsync(...);
Task continued = tmp.ContinueWith( continuation );
return continued;
}
private .. continuation()
{
int x = 5;
}
Note how there's no wait/sleep/etc. However, the int x=5 is delayed, until the original task returned from PostAsync notifies everyone that it has just completed.
Note how original task from firebase gets a 'continuation' chained to it, but a different task is returned: the continuation-task.
This means that the await (if you add it there of course) in MapData awaits not for just the firebase task, but for firebasetask+contination.
If there were more awaits in the AddData method, there would be more slices, more chained continuations, but the task that is eventually returned to the caller covers it all.
Now, any awaits in the MapData would do the same: it would split the code, register a continuation, and return the resulting task for someone to observe it.
The caller will get a Task again. But the caller doesn't realy HAVE TO await it. The called may run a thread that will await for the task. The caller may attach a continuation. Or put the task onto some queue and hand it off for someone else to handle. I mean that the async/await look like 'contagious disease' that always propagates upwards, but you can stop at any time it if you really need.
Also, as you already noted, the caller of AddData does not have to await that task, if the caller is not worried about the order of operations further down in the code. If the Pins.Add is allowed to run before firebase task completes, it's fine to not await for AddData. That's why not-awaiting an async method is not a compilation error. You will probably get a warning though, because the AddData returns a Task and that Task is ignored (not awaited, not stored, not chained .ContinueWith etc).
This should work...
public async Task MapPage()
{
Task t = AddData(1, result, DateTime.Now, deviceId);
await t;
customMap.Pins.Add(new CustomPin
{
..//
});
}
Continuation...
Mi Po follow up question::
would this also work as a solution?
public async Task MapPage()
{
await AddData(1, result, DateTime.Now, deviceId);
customMap.Pins.Add(new CustomPin { ..// });
}
Yes it would work...but in your particular case your doing an http post and you need (IMO) to check the result (status code) to determine what to do next. Something along these lines...
public async Task MapPage()
{
HttpResponseMessage result = await AddData(1, result, DateTime.Now, deviceId);
if (result.IsSuccessStatusCode)
{
customMap.Pins.Add(new CustomPin { ... });
}
else
{
...
}
}
You would also need to change AddData to return the responce
Typically, I do the following
public static async Task dosth()
{
List<Task> job = new List<Task>();
for (int i = 0; i < 3; i++)
{
job.Add(sleep());
}
Task.WhenAll(job.ToArray());
}
static async Task sleep()
{
await Task.Delay(1000);
Console.WriteLine("Finish new");
}
It works smoothly, no problem. But when I do a review on my own code (trying using other syntax to do the same job), I suddenly figure out the following two are different.
public static async Task dosthA()
{
//This will be working synchronously, take 3 seconds.
await sleep();
await sleep();
await sleep();
//This will be working asynchronously, take 1 second only.
Task A = sleep();
Task B = sleep();
Task C = sleep();
await A;
await B;
await C;
}
Why assigning the async function to a new variable make difference? I originally think they are the same.
Update
Why it is confusing me is, actually in Microsoft doc on Async-await,
They stated the following in their code.
// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();
They are actually different, why they use //or , in a single statement, just because it makes no different in their own example?
This is because when you are returning a running Task when you call Sleep() even when you're assigning to a variable.
The confusion is that the Task does not begin if you assign it to a variable (A, B, or C) until you call await A; but that's not true. As soon as you assign sleep(); to A, sleep() was called; therefore the Task in the sleep() method is running. Assigning it to a variable or not the Task begins when you call the method; because in the method you start the Task.
Knowing this; when you call:
await A;
await B;
await C;
A, B, and C, have already starting simultaneously... After awaiting A it is most likely B, and C have also completed or are milliseconds from completing.
There are situations where you can reference a Task that hasn't started yet but you would have to purposely return a non-running Task to do that.
To answer the edit to your question also.
Tasks have a method called GetAwaiter() which returns a TaskAwaiter. In C# when you write var task = sleep(); then you're assigning the actual Task to the task variable. All the same when you write await sleep(); the compiler does some cool stuff and it actually calls the Task.GetAwaiter() method; which is subscribed to. The Task will run and when it is complete the TaskAwaiter fires the continuation action. This can't be explained in a simple answer but to know the outer logic helps.
Among other things the TaskAwaiter implements ICriticalNotifyCompletion which in turn implements INotifyCompletion. Both have one method each, OnCompleted(Action) and UnsafeOnCompleted(Action) (you can guess which is which by naming convention).
Another thing to note is that Task.GetAwaiter() returns a TaskAwaiter but Task<TResult>.GetAwaiter() returns a TaskAwaiter<TResult>. There's not a strong difference in the two but there is a difference in the GetResult() method of the two tasks; which is what's called while marshalling back to the proper threading context. The TaskAwaiter.GetResult() returns void and the TaskAwaiter<TResult>.GetResult() returns TResult.
I feel like if I push further into this I'll have to write pages to explain it all in detail... Hopefully just explaining your question and pulling the curtain back a little bit will shed enough light to help you both understand and dig deeper if you're more curious.
Ok, so based on the comment below I want to describe my answer a little bit further.
I'll start this simple; let's just make a Task; one that isn't running, and look at it first.
public Task GetTask()
{
var task = new Task(() => { /*some work to be done*/ });
//Now we have a reference to a non-running task.
return task;
}
We can now call code like:
public async void DoWork()
{
await GetTask();
}
… but we'll be waiting forever; until the application ends, because the Task was never started. However; we could do something like this:
public async void DoWork()
{
var task = GetTask();
task.Start();
await task;
}
… and it will await the running Task and continue once the Task is complete.
Knowing this you can make as many calls to GetTask() as you like and you'll only be referencing Tasks that have not started.
In your code it's just the opposite, which is fine, as this is the most used way. I encourage you to make sure your method names notify the user of how you're returning the Task. If the Task is already running the most common convention is the end the method name with Async. Here's another example doing it with a running Task for clarity.
public Task DoTaskAsync()
{
var task = Task.Run(() => { /*some work to be done*/ });
//Now we have a reference to a task that's already running.
return task;
}
And now we will most likely call this method like:
public async void DoWork()
{
await DoTaskAsync();
}
However; note that if we simply want to reference the Task just like we did earlier, we can, the only difference is this Task is running where the one prior was not. So this code is valid.
public async void DoWork()
{
var task = DoTaskAsync();
await task;
}
The big take away is how C# handles the async / await keywords. async tells the compiler that the method is going to become a continuation of a Task. In short; the compiler knows to look for all await calls and put the rest of the method in a continuation.
The await keyword tells the compiler to call the Task.GetAwaiter() method on the Task ( and basically subscribe to the INotifyCompletion and ICriticalNotifyCompletion) to signal the continuation in the method.
And this I wanted to add just incase you weren't aware. If you do have more than one task that you want to await but would rather await one task as if they were all one then you can do that with Task.WhenAll() So instead of:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await taskA;
await taskB;
await taskC;
You could write it a little cleaner like so:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await Task.WhenAll(taskA, taskB, taskC);
And there are more ways of doing this sort of thing built in; just explore it.
Lets say I have a method defined as follows:
public async Task CreateUser()
{
await GetUserDetails();
GetUserOrder();
}
private void GetUserDetails() {
private void GetUserOrder() {
Does the method GetUserDetails(); and GetUserOrder() have to be async as well to avoid UI blocking ?
I cannot await the GetUserDetails() method since it is not async. How can I achieve this in c# ? I want to ensure all these methods are invoked step by step.
The relevant question is in a comment:
How can I ensure all my methods are invoked completely sequentially?
The fact that you're asking the question indicates that you don't understand what "await" is. Await is the sequencing operation on a asynchronous workflows. An await means this workflow will not proceed until the awaited task is complete. It's an asynchronous wait, hence the name await.
Consider this question: in a synchronous workflow, what is the sequencing operation?
No, really, give it some thought.
.
.
.
It is ;. When you say
fResult = foo();
bResult = bar();
qResult = qux();
that means that foo has to finish completely before bar can begin. That is not true for asynchronous workflows. If we have
fTask = fooAsync();
bTask = barAsync();
qTask = quxAsync();
Then the asynchronous operations can complete in any order. If we say
await fooAsync();
await barAsync();
await quxAsync();
Then barAsync will not start until fooAsync's task completes. await sequences the asynchronous workflow. The difference is that the thread can continue to do other unrelated work while asynchronously waiting for foo to complete, which is not true in a synchronous workflow; in a synchronous workflow the thread is already busy computing the foo result, so it can't do other work.
yes if you want to wait than you have to write await for that methods also. because after first await your code agian will be synchronous ..and if UI thread than it will run on it.
1.you code will be , so by this code you code become asynchronous for GetUserORder also. you just have to wrap method in Task construct and return
public async Task CreateUser()
{
await GetUserDetails();
await Task.Factory.SartNew(()=> GetUserOrder());
}
2.or you can do this also
public async Task CreateUser()
{
await Task.Factory.SartNew(()=>{
GetUserDetails();
GetUserOrder(); });
}
3.or you can do like this also, in below code will not wait for getuserorder method and excute await one method
public async Task CreateUser()
{
Task.Factory.SartNew(()=> GetUserOrder()).ContinueWith((t)=> Console.WriteLine("Completed");
await GetUserDetails();
}
4.or last one variation, here you start GetUserOrder first and dont wait for it than you call GetUserDetails in async fashion , and if you want to work on GetUserOrder method want to wait just use Wait method.
public async Task CreateUser()
{
var task = Task.Factory.SartNew(()=> GetUserOrder());
await GetUserDetails();
if(!task.IsCompleted)
task.Wait();
}
in your case you can go for 3 and if you want to wait go for 4th one.
As you asked me in comment what is difference between Task.Run and statnew method -: for that you can check this SO question : Regarding usage of Task.Start() , Task.Run() and Task.Factory.StartNew()
You should put await only in front of async methods. To run a synchronous one that you don't want to wait, you can use a new thread from the tread pool:
new Thread(() => DoSomething()).Start();
or
Task.Factory.SartNew(()=> DoSomething());
Here is the help page: https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx
Otherwise, your call to GetUserDetails will have to finish before you execute the next line.
Almost every SO's answer regarding this topic , states that :
LINQ doesn't work perfectly with async
Also :
I recommend that you not think of this as "using async within LINQ"
But in Stephen's book there is a sample for :
Problem: You have a collection of tasks to await, and you want to do some
processing on each task after it completes. However, you want to do
the processing for each one as soon as it completes, not waiting for
any of the other tasks.
One of the recommended solutions was :
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(async t =>
{
var result = await t;
Trace.WriteLine(result);
}).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
Question #1:
I don't understand why now async inside a LINQ statement - does work . Didn't we just say "don't think about using async within LINQ" ?
Question #2:
When the control reaches the await t here — What is actually happen? Does the control leaves the ProcessTasksAsync method ? or does it leaves the anonymous method and continue the iteration ?
I don't understand why now async inside a LINQ statement - does work . Didn't we just say "don't think about using async within LINQ" ?
async mostly doesn't work with LINQ because IEnumerable<T> extensions don't always infer the delegate type properly and defer to Action<T>. They have no special understanding of the Task class. This means the actual async delegate becomes async void, which is bad. In the case of Enumerable.Select, we have an overload which returns a Func<T> (which in turn will be Func<Task> in our case), which is equivalent to async Task, hence it works fine for async use-cases.
When the control reaches the await t here — What is actually happen? Does the control leaves the ProcessTasksAsync method ?
No, it doesn't. Enumerable.Select is about projecting all elements in the sequence. This means that for each element in the collection, await t which will yield control back to the iterator, which will continue iterating all elements. That's why you later have to await Task.WhenAll, to ensure all elements have finished execution.
Question 1:
The difference is that each task is continued with additional processing which is: Trace.WriteLine(result);. In the link you pointed to, that code does not change anything, just creates overhead of awaiting and wrapping with another task.
Question 2:
When the control reaches the await t here — What is actually happen?
It awaits for the result of ProcessTasksAsync's task, then continue with Trace.WriteLine(result);. We can say that the control leaves the ProcessTasksAsync method when we have the result and the processing is still inside the anonymous method.
At the end, we have await Task.WhenAll(processingTasks); which will await for all tasks including the additional processing (Trace.WriteLine(result);) to complete before continuing but each task does not await for the others to continue executing: Trace.WriteLine(result);
It will be better this way:
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
static async Task AwaitAndProcessAsync(Task<int> task)
{
var result = await task;
Console.WriteLine(result);
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(AwaitAndProcessAsync).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
Array of Task, because AwaitAndProcessAsync returns Task.