async await code executing not as expected - c#

I created a simple example to understand async/await in C#.
class Program
{
static void Main(string[] args)
{
var t = BarAsync();
Console.WriteLine("Main");
}
private static async Task BarAsync()
{
Console.WriteLine("This happens before await");
int i = await QuxAsync();
Console.WriteLine("This happens after await. This result of await is " + i);
}
private static Task<int> QuxAsync()
{
int c = 0;
for (int i = 0; i < int.MaxValue; i++)
{
c++;
}
Console.WriteLine("in the middle processing...");
return Task.FromResult(c);
}
}
So the program prints This happens before await first then count the value from a return method. Afterwards it prints the result.
It looks good. My question is that since await doesn't block the thread that evaluates the async method. My understanding is if the async takes a long time it will return to its calling method.
For my example, because QuxAsync() takes a long time, the code
Console.WriteLine("Main");
is not blocked and will be evaluated very soon.
I think the print order should be
This happens before await
Main
in the middle processing...
This happens after await. This result of await is 2147483647
However it is not, why?

I'll second (third?) others' recommendations that you continue reading and learning about async. I'm partial to my own async intro, but these days there are a number of good ones out there.
My question is that since await doesn't block the thread that evaluates the async method. My understanding is if the async takes a long time it will return to its calling method.
This is the part that is wrong. Asynchrony has absolutely nothing to do with how long something takes.
There's two pieces of knowledge missing, both covered in my async intro.
First: await works by first checking its argument. If it is already completed, then await continues executing - synchronously.
Second: every method is called synchronously. Including async methods. The only time asynchrony happens is when an async method has an await whose argument is not already completed; in that case, that async method returns an incomplete task.
Putting both of these together should explain why your code actually runs synchronously.

Related

C# Async, why we need to "hold" the console to get the async result?

For the past several days, I've been trying to figure out why my async method is not working and its a very simple piece of code.
public class EntryPoint
{
static void Main()
{
RunTheTaskAsync();
//Console.ReadLine(); // if I add this to "hold" the finish of the project, I will see the result, without it I dont
}
public async static void RunTheTaskAsync()
{
Task<string> task = Concatenator('1', 200000);
Console.WriteLine("Heeeelllooooooo");
Console.WriteLine("I am running while Concatenator is concatenating in the background.");
Console.WriteLine("You will receive the results shortly");
string result = await task;
Console.WriteLine("Result is: " + result.Length);
}
public static Task<string> Concatenator(char characterToConcatenate, int count)
{
Console.WriteLine("Concatenating!");
return Task<string>.Factory.StartNew(() =>
{
string concatenatedString = "";
for (int i = 0; i < count; i++)
{
concatenatedString += characterToConcatenate;
}
return concatenatedString;
});
}
}
If I run it as it is in the example above, I never get to see the result, I only see the Console.WriteLine's and Press any key to continue.. after that no result.
If I uncomment the Console.ReadLine(); everything works as I am expecting it to work and I simply cant understand why!?! The same is true if I add some Thread.Sleep(xxx) or another piece of code that will take longer to execute than the "Concatenator" method.
Isn't this one of the issues that await should solve on its own, its kind of implied from its very name.
The way I understand it is:
The Task method starts executing on the background
We proceed with the 3 ConsoleWritelines in the async method
Since there is nothing else to do and the task is not completed yet, we get to the await line and we should await for the task
to be completed and then proceed with the rest of the code.
It works like this ONLY if have another piece of code inbetween that will take longer than the Task method to execute, or if I use the Console.ReadLine() and I just cant find an explanation about this!
I also have a secondary question regarding the syntax of my implementation. Is this the proper way to create a Task method? By using
public Task<T> SomeMethodName(some, args)
{
return Task<T>Factory.StartNew(() =>
{
somecode that returns T;
});
}
async voids (like your RunTheTaskAsync method) are "fire and forget". You can't track their progress and almost never want to use them.
Instead, make an async Task and await it:
static async Task Main()
{
await RunTheTaskAsync();
}
public static async Task RunTheTaskAsync()
{
...
}
For more details, see:
Async/Await - Best Practices in Asynchronous Programming
Note: Visual Studio prior to 2017 Update 3 does not support an async Main method. In that case, you have to manually await the Task:
static void Main()
{
RunTheTaskAsync().GetAwaiter().Wait();
}
About your second question (for the future: SO's policy is "one question per question"): Yes, Task.Factory.StartNew is correct if you need your task to run in a separate thread. Newer versions of .NET as offer Task.Run as a shortcut, see the following question for details:
What is the difference between Task.Run() and Task.Factory.StartNew()

How do I actually write/end an async method in c#?

I get that I need to await thing in an async marked method to make it asynchronous, but I don't get how to actually end the hole it makes.
static async void Example()
{
int t = await getIntAsync();
WriteLine($"computer: {t}");
}
Since getIntAsync is marked async I have to await in that method or I get a warning. But oh no in the method I await on in getIntAsync I have to mark that as aasync, then unless there is an await in there I get a warning. And so on and so forth to infinity it seems. How do I just make it stop?
I've had a few people tell me to put
await Task.Delay(1000);
In my code, but I know the answer can't be as smelly as putting a delay of a second in all my production code.
A couple others said a task method to end it such as
static Task task()
{
//code
}
But unless I mark that async it throws the same warning that got me into this confusion. I know
static Task task()
{
//code
return Task.FromResult(0);
}
Technically it works, but again that seems too much of a code smell to have all over production.
I just don't get it...
EDIT:
Because it was asked for. I know its a very trivial method, but its also just one I'm using for practice.
static async Task<int> getIntAsync()
{
Console.Write("Enter the number: ");
int n = int.Parse(Console.ReadLine());
return n;
}
What is confusing here is that you don't really do something asynchronous. Console.ReadLine() is a synchronous method. Simply typing async or await somewhere does not magically make this asynchronous.
Since this code is only for testing and learning, one way to make it asynchronous is to put it on another thread using Task.Run() (I would not suggest this for many cases in production code):
static Task<int> getIntAsync()
{
Console.Write("Enter the number: ");
return Task.Run(() => int.Parse(Console.ReadLine());
}
There is no async keyword needed here as you are not awaiting something. You just return a Task<int> that is completed when the user has entered a value and that value was parsed.
And your Example() method then works like that:
static async void Example()
{
int t = await getIntAsync();
WriteLine($"computer: {t}");
}
When the await is hit, the control flow is returned to the caller and the rest of this method (the assignment to t and the call to Console.WriteLine()) are scheduled as a continuation that is executed when the Task<int> returned by getIntAsync() has finished.
The following is needed (async keyword is required and so is the await, it's simply best practice):
The Async keyword
The Await keyword
Some process that you want to work independently while the asynchorous process runs.
Typically, you return value comes from your await task (which should fill in the end hole).
Here is example using a StreamReader,
async Task<string> GetStringFromReaderAsync()
{
Streamreader sr = new StreamReader("filename.txt");
Task<string> getStringTask = sr.ReadLineAsync("filepath");
//Allow user to continue with some other work.
DoFileLookup();
string result = await sr.getStringTask();
return result.ToString();
}
More information here: https://msdn.microsoft.com/en-us/library/system.io.streamreader.readlineasync(v=vs.110).aspx
More about Async and Await: https://msdn.microsoft.com/en-us/library/mt674882.aspx
static async Task<int> getIntAsync()
{
Console.Write("Enter the number: ");
int n = int.Parse(Console.ReadLine());
return n;
}
This will run synchronously as there is no await statement And no awaited call to an async method
the general idea is this
public async Task<int> ExecuteAsync() //Method return type is Task<int>
{
// Error: return type is not int. Return type is Task<int>
return db.SaveChangesAsync();
// OK: returns a task handle that you can await on in you code that called ExecuteAsync()
// you thread continues processing in your calling function until you try to read the value from this return statement.
return await db.SaveChangesAsync();
// Ok. Your Thread leaves here and returns when result available.
// no further Processing done in calling function
return db.SaveChangesAsync().Result;
// Ok. This is not required in this case,
// but if you have an async method that has multiple return points,
// and one of them does not depend on an async method, you can wrap
// the output e.g. return await Task.FromResult(0);
return await Task.FromResult(db.SaveChangesAsync().Result);
return 0; //also ok.
}
Adding on to the other answer below.
static async Task<int> GetIntAsync()
{
Console.Write("Enter the number: ");
return await Task.Run(() => int.Parse("1"));
}
This approach makes something that runs synchronously to be wrapped in a task. However you should never do this (unless of course you know what you are doing) as this spawns another thread. One use case where I have used this is for offloading in webservers but otherwise generally its a bad idea. So while you may have begin with the intention of have maximum utilization of a single thread, you have now ended up with two thread working.

Inside a loop,does each async call get chained to the returned task using task's continuewith?

The best practice is to collect all the async calls in a collection inside the loop and do Task.WhenAll(). Yet, want to understand what happens when an await is encountered inside the loop, what would the returned Task contain? what about further async calls? Will it create new tasks and add them to the already returned Task sequentially?
As per the code below
private void CallLoopAsync()
{
var loopReturnedTask = LoopAsync();
}
private async Task LoopAsync()
{
int count = 0;
while(count < 5)
{
await SomeNetworkCallAsync();
count++;
}
}
The steps I assumed are
LoopAsync gets called
count is set to zero, code enters while loop, condition is checked
SomeNetworkCallAsync is called,and the returned task is awaited
New task/awaitable is created
New task is returned to CallLoopAsync()
Now, provided there is enough time for the process to live, How / In what way, will the next code lines like count++ and further SomeNetworkCallAsync be executed?
Update - Based on Jon Hanna and Stephen Cleary:
So there is one Task and the implementation of that Task will involve
5 calls to NetworkCallAsync, but the use of a state-machine means
those tasks need not be explicitly chained for this to work. This, for
example, allows it to decide whether to break the looping or not based
on the result of a task, and so on.
Though they are not chained, each call will wait for the previous call to complete as we have used await (in state m/c, awaiter.GetResult();). It behaves as if five consecutive calls have been made and they are executed one after the another (only after the previous call gets completed). If this is true, we have to be bit more careful in how we are composing the async calls.For ex:
Instead of writing
private async Task SomeWorkAsync()
{
await SomeIndependentNetworkCall();// 2 sec to complete
var result1 = await GetDataFromNetworkCallAsync(); // 2 sec to complete
await PostDataToNetworkAsync(result1); // 2 sec to complete
}
It should be written
private Task[] RefactoredSomeWorkAsync()
{
var task1 = SomeIndependentNetworkCall();// 2 sec to complete
var task2 = GetDataFromNetworkCallAsync()
.ContinueWith(result1 => PostDataToNetworkAsync(result1)).Unwrap();// 4 sec to complete
return new[] { task1, task2 };
}
So that we can say RefactoredSomeWorkAsync is faster by 2 seconds, because of the possibility of parallelism
private async Task CallRefactoredSomeWorkAsync()
{
await Task.WhenAll(RefactoredSomeWorkAsync());//Faster, 4 sec
await SomeWorkAsync(); // Slower, 6 sec
}
Is this correct? - Yes. Along with "async all the way", "Accumulate tasks all the way" is good practice. Similar discussion is here
When count is zero, new task will be created because of await and be returned
No. It will not. It will simply call the async method consequently, without storing or returning the result. The value in loopReturnedTask will store the Task of LoopAsync, not related to SomeNetworkCallAsync.
await SomeNetworkCallAsync(); // call, wait and forget the result
You may want to read the MSDN article on async\await.
To produce code similar to what async and await do, if those keywords didn't exist, would require code a bit like:
private struct LoopAsyncStateMachine : IAsyncStateMachine
{
public int _state;
public AsyncTaskMethodBuilder _builder;
public TestAsync _this;
public int _count;
private TaskAwaiter _awaiter;
void IAsyncStateMachine.MoveNext()
{
try
{
if (_state != 0)
{
_count = 0;
goto afterSetup;
}
TaskAwaiter awaiter = _awaiter;
_awaiter = default(TaskAwaiter);
_state = -1;
loopBack:
awaiter.GetResult();
awaiter = default(TaskAwaiter);
_count++;
afterSetup:
if (_count < 5)
{
awaiter = _this.SomeNetworkCallAsync().GetAwaiter();
if (!awaiter.IsCompleted)
{
_state = 0;
_awaiter = awaiter;
_builder.AwaitUnsafeOnCompleted<TaskAwaiter, TestAsync.LoopAsyncStateMachine>(ref awaiter, ref this);
return;
}
goto loopBack;
}
_state = -2;
_builder.SetResult();
}
catch (Exception exception)
{
_state = -2;
_builder.SetException(exception);
return;
}
}
[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0)
{
_builder.SetStateMachine(param0);
}
}
public Task LoopAsync()
{
LoopAsyncStateMachine stateMachine = new LoopAsyncStateMachine();
stateMachine._this = this;
AsyncTaskMethodBuilder builder = AsyncTaskMethodBuilder.Create();
stateMachine._builder = builder;
stateMachine._state = -1;
builder.Start(ref stateMachine);
return builder.Task;
}
(The above is based on what happens when you use async and await except that the result of that uses names that cannot be valid C# class or field names, along with some extra attributes. If its MoveNext() reminds you of an IEnumerator that's not entirely irrelevant, the mechanism by which await and async produce an IAsyncStateMachine to implement a Task is similar in many ways to how yield produces an IEnumerator<T>).
The result is a single Task which comes from AsyncTaskMethodBuilder and makes use of LoopAsyncStateMachine (which is close to the hidden struct that the async produces). Its MoveNext() method is first called upon the task being started. It will then use an awaiter on SomeNetworkCallAsync. If it is already completed it moves on to the next stage (increment count and so on), otherwise it stores the awaiter in a field. On subsequent uses it will be called because the SomeNetworkCallAsync() task has returned, and it will get the result (which is void in this case, but could be a value if values were returned). It then attempts further loops and again returns when it is waiting on a task that is not yet completed.
When it finally reaches a count of 5 it calls SetResult() on the builder, which sets the result of the Task that LoopAsync had returned.
So there is one Task and the implementation of that Task will involve 5 calls to NetworkCallAsync, but the use of a state-machine means those tasks need not be explicitly chained for this to work. This, for example, allows it to decide whether to break the looping or not based on the result of a task, and so on.
When an async method first yields at an await, it returns a Task (or Task<T>). This is not the task being observed by the await; it is a completely different task created by the async method. The async state machine controls the lifetime of that Task.
One way to think of it is to consider the returned Task as representing the method itself. The returned Task will only complete when the method completes. If the method returns a value, then that value is set as the result of the task. If the method throws an exception, then that exception is captured by the state machine and placed on that task.
So, there's no need for attaching continuations to the returned task. The returned task will not complete until the method is done.
How / In what way, will the next code lines like count++ and further SomeNetworkCallAsync be executed?
I do explain this in my async intro post. In summary, when a method awaits, it captures a "current context" (SynchronizationContext.Current unless it is null, in which case it uses TaskScheduler.Current). When the await completes, it resumes executing its async method within that context.
That's what technically happens; but in the vast majority of cases, this simply means:
If an async method starts on a UI thread, then it will resume on that same UI thread.
If an async method starts within an ASP.NET request context, then it will resume with that same request context (not necessarily on the same thread, though).
Otherwise, the async method resumes on a thread pool thread.

Entity Framework SaveChanges() vs. SaveChangesAsync() and Find() vs. FindAsync()

I have been searching for the differences between 2 pairs above but haven't found any articles explaining clearly about it as well as when to use one or another.
So what is the difference between SaveChanges() and SaveChangesAsync()?
And between Find() and FindAsync()?
On server side, when we use Async methods, we also need to add await. Thus, I don't think it is asynchronous on server side.
Does it only help to prevent the UI blocking on client side browser? Or are there any pros and cons between them?
Any time that you need to do an action on a remote server, your program generates the request, sends it, then waits for a response. I will use SaveChanges() and SaveChangesAsync() as an example but the same applies to Find() and FindAsync().
Say you have a list myList of 100+ items that you need to add to your database. To insert that, your function would look something like so:
using(var context = new MyEDM())
{
context.MyTable.AddRange(myList);
context.SaveChanges();
}
First you create an instance of MyEDM, add the list myList to the table MyTable, then call SaveChanges() to persist the changes to the database. It works how you want, the records get committed, but your program cannot do anything else until the commit finishes. This can take a long time depending on what you are committing. If you are committing changes to the records, entity has to commit those one at a time (I once had a save take 2 minutes for updates)!
To solve this problem, you could do one of two things. The first is you can start up a new thread to handle the insert. While this will free up the calling thread to continue executing, you created a new thread that is just going to sit there and wait. There is no need for that overhead, and this is what the async await pattern solves.
For I/O opperations, await quickly becomes your best friend. Taking the code section from above, we can modify it to be:
using(var context = new MyEDM())
{
Console.WriteLine("Save Starting");
context.MyTable.AddRange(myList);
await context.SaveChangesAsync();
Console.WriteLine("Save Complete");
}
It is a very small change, but there are profound effects on the efficiency and performance of your code. So what happens? The begining of the code is the same, you create an instance of MyEDM and add your myList to MyTable. But when you call await context.SaveChangesAsync(), the execution of code returns to the calling function! So while you are waiting for all those records to commit, your code can continue to execute. Say the function that contained the above code had the signature of public async Task SaveRecords(List<MyTable> saveList), the calling function could look like this:
public async Task MyCallingFunction()
{
Console.WriteLine("Function Starting");
Task saveTask = SaveRecords(GenerateNewRecords());
for(int i = 0; i < 1000; i++){
Console.WriteLine("Continuing to execute!");
}
await saveTask;
Console.Log("Function Complete");
}
Why you would have a function like this, I don't know, but what it outputs shows how async await works. First let's go over what happens.
Execution enters MyCallingFunction, Function Starting then Save Starting gets written to the console, then the function SaveChangesAsync() gets called. At this point, execution returns to MyCallingFunction and enters the for loop writing 'Continuing to Execute' up to 1000 times. When SaveChangesAsync() finishes, execution returns to the SaveRecordsfunction, writing Save Complete to the console. Once everything in SaveRecords completes, execution will continue in MyCallingFunction right were it was when SaveChangesAsync() finished. Confused? Here is an example output:
Function Starting
Save Starting
Continuing to execute!
Continuing to execute!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Save Complete!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Function Complete!
Or maybe:
Function Starting
Save Starting
Continuing to execute!
Continuing to execute!
Save Complete!
Continuing to execute!
Continuing to execute!
Continuing to execute!
....
Continuing to execute!
Function Complete!
That is the beauty of async await, your code can continue to run while you are waiting for something to finish. In reality, you would have a function more like this as your calling function:
public async Task MyCallingFunction()
{
List<Task> myTasks = new List<Task>();
myTasks.Add(SaveRecords(GenerateNewRecords()));
myTasks.Add(SaveRecords2(GenerateNewRecords2()));
myTasks.Add(SaveRecords3(GenerateNewRecords3()));
myTasks.Add(SaveRecords4(GenerateNewRecords4()));
await Task.WhenAll(myTasks.ToArray());
}
Here, you have four different save record functions going at the same time. MyCallingFunction will complete a lot faster using async await than if the individual SaveRecords functions were called in series.
The one thing that I have not touched on yet is the await keyword. What this does is stop the current function from executing until whatever Task you are awaiting completes. So in the case of the original MyCallingFunction, the line Function Complete will not be written to the console until the SaveRecords function finishes.
Long story short, if you have an option to use async await, you should as it will greatly increase the performance of your application.
My remaining explanation will be based on the following code snippet.
using System;
using System.Threading;
using System.Threading.Tasks;
using static System.Console;
public static class Program
{
const int N = 20;
static readonly object obj = new object();
static int counter;
public static void Job(ConsoleColor color, int multiplier = 1)
{
for (long i = 0; i < N * multiplier; i++)
{
lock (obj)
{
counter++;
ForegroundColor = color;
Write($"{Thread.CurrentThread.ManagedThreadId}");
if (counter % N == 0) WriteLine();
ResetColor();
}
Thread.Sleep(N);
}
}
static async Task JobAsync()
{
// intentionally removed
}
public static async Task Main()
{
// intentionally removed
}
}
Case 1
static async Task JobAsync()
{
Task t = Task.Run(() => Job(ConsoleColor.Red, 1));
Job(ConsoleColor.Green, 2);
await t;
Job(ConsoleColor.Blue, 1);
}
public static async Task Main()
{
Task t = JobAsync();
Job(ConsoleColor.White, 1);
await t;
}
Remarks: As the synchronous part (green) of JobAsync spins longer than the task t (red) then the task t is already completed at the point of await t. As a result, the continuation (blue) runs on the same thread as the green one.
The synchronous part of Main (white) will spin after the green one is finished spinning. That is why the synchronous part in asynchronous method is problematic.
Case 2
static async Task JobAsync()
{
Task t = Task.Run(() => Job(ConsoleColor.Red, 2));
Job(ConsoleColor.Green, 1);
await t;
Job(ConsoleColor.Blue, 1);
}
public static async Task Main()
{
Task t = JobAsync();
Job(ConsoleColor.White, 1);
await t;
}
Remarks: This case is opposite to the first case. The synchronous part (green) of JobAsync spins shorter than the task t (red) then the task t has not been completed at the point of await t. As a result, the continuation (blue) runs on the different thread as the green one.
The synchronous part of Main (white) still spins after the green one is finished spinning.
Case 3
static async Task JobAsync()
{
Task t = Task.Run(() => Job(ConsoleColor.Red, 1));
await t;
Job(ConsoleColor.Green, 1);
Job(ConsoleColor.Blue, 1);
}
public static async Task Main()
{
Task t = JobAsync();
Job(ConsoleColor.White, 1);
await t;
}
Remarks: This case will solve the problem in the previous cases about the synchronous part in asynchronous method. The task t is immediately awaited. As a result, the continuation (blue) runs on the different thread as the green one.
The synchronous part of Main (white) will spin immediately parallel to JobAsync.
If you want to add other cases, feel free to edit.
This statement is incorrect:
On server side, when we use Async methods, we also need to add await.
You do not need to add "await", await is merely a convenient keyword in C# that enables you to write more lines of code after the call, and those other lines will only get executed after the Save operation completes. But as you pointed out, you could accomplish that simply by calling SaveChanges instead of SaveChangesAsync.
But fundamentally, an async call is about much more than that. The idea here is that if there is other work you can do (on the server) while the Save operation is in progress, then you should use SaveChangesAsync. Do not use "await". Just call SaveChangesAsync, and then continue to do other stuff in parallel. This includes potentially, in a web app, returning a response to the client even before the Save has completed. But of course, you still will want to check the final result of the Save so that in case it fails, you can communicate that to your user, or log it somehow.

Looking for guidance to understand how asynchronous Programming with Async and Await works

i go through a msdn sample code where a function is called when button is clicked and when routine is called then Await keyword is used and function has async keyword used.
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
int contentLength = await AccessTheWebAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
When AccessTheWebAsync is called then await keyword is used, what does it mean?
When this function AccessTheWebAsync() will be executing then DoIndependentWork() function is called and i guess here control will be waiting until this function DoIndependentWork() is finished. Am I right?
again there is another statement called
string urlContents = await getStringTask;
why they use here await. if we do not use await here then what would happen?
Please guide me to understand the code that how it is working.
I have an intro blog post here, and the MSDN docs are also extremely good.
You can think of await as "pausing" the method (without blocking the thread) until the awaitable operation completes. When this happens, it returns a task that is not completed to the calling method, so it also has the option to await.
Here's a brief description about async/await methods.
Async Methods:
Caller is not necessarily blocked for the full execution of async
method
Possible return types
void: “fire-and-forget”
Task: allows to await termination of async method
Task<T>: allows to await termination and get result of type T
No ref or out parameter for async methods
Must again contain an await => Otherwise compile warning
await for Tasks
Await termination of a TPL task
Return result of task (if task with
result type)
Must only occur in async methods => Otherwise compile error
An async method is partly synchronous and partly asynchronous
Caller synchronously executes the method until a blocking await
Thereafter, the method rest is asynchronously executed
async & await Mechanism
Efficient
public async Task<int> GetSiteLengthAsync(string url)
{
HttpClient client = new HttpClient(); <= Sync
Task<string> download1 = client.GetStringAsync(url); <= Sync
string site1 = await download1; <= Async (Another thread)
return site1.Length; <= Async (Another thread)
}
Not sure if that simplier for you to understand that in the following way, but this is how it helped myself:
As you can see, the AccessTheWebAsync returns Task<int> but not just int.
If you would have called it without "await", you would just get the Task<int> object as its result. And could do anything further you want (manually) with that task: for instance, to wait until it finishes theTask.Wait(); and obtain the result of int in theTask.Result.
But await does all that instead of you and returns just int: Task<int> => int.
This is it.
from MSDN:
the await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.await does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
So when the compiler encounter
int contentLength = await AccessTheWebAsync();
it waits till the AccessTheWebAsync() task is complted
please take a look at this example C# Async,Await
All await does is blocks the thread until the result of an async operation returns.
Edit: sorry when I said block I should have said suspend, since blocking would prevent execution from continuing!
Edit2: As Alex pointed out - I should have probably said "execution is suspended" rather than the thread. Basically "Stuff happens until await returns but the point is it appears you are writing and executing synchronous code"
Since async operations have the potential to be take a while (e.g. web service calls), they tend to use callbacks to return a result.
If you have to handle callbacks in your code it can get a little messy, especially when waiting on multiple async tasks that are dependant on each other. Async/await and Task simplify the code so that you can write async code literally in the order you would read it.
e.g. example standard async code with callbacks:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.SomeAsyncServiceCall((svcResult) => { result = svcResult.Value; });
return result;
}
and if you have multiple calls that need to be chained:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.GetSomeIdentifier((svcResult) =>
{
var identifier = svcResult.Value;
WebService.GetResult(identifier, (anotherResult) =>
{
result = anotherResult.Value;
}
}
);
return result;
}
As you can see, it starts getting messy, the code doesn't really read in an order that feels natural. The alternative is to use callback methods instead of anonymous methods but still, the callback methods are far away from the code that called them and things can feel disjointed
The other alternative is of course async/await which is much clearer
public int CallSomeServiceAndReturnItsValue()
{
int identifier = await WebService.GetSomeIdentifier();
return await WebService.GetResult(identifier);
}

Categories