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 await
s 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).