C
C#12mo ago
Blank

✅ Confused about Asynchronous Programming

I have been reading about Asynchronous programming for a long time but the concepts are not going through me. From what I learnt, one way of calling async tasks is like this:
var task1 = sometask();
// Do something else
var result = await task1;
var task1 = sometask();
// Do something else
var result = await task1;
Okay so I understand this one. A task is started, some other work is done, and then the task is asked to return the result. But what about this one:
var result = await someTask();
// Do something else
var result = await someTask();
// Do something else
Now how is this different from calling the method synchronously? We called the task and are now waiting for it to finish the next moment. Also, some articles say that the await keyword suspends the execution of the current method and returns the control to the caller. From what I understand, its like:
static async Task Main()
{
await someTask();
Console.WriteLine(1);
}

static async Task someTask()
{
// Do something
await someOtherTask();
// Do something else
Console.WriteLine(2);
}
static async Task Main()
{
await someTask();
Console.WriteLine(1);
}

static async Task someTask()
{
// Do something
await someOtherTask();
// Do something else
Console.WriteLine(2);
}
The 1 will be printed to the console before 2. But its not the case. Please explain... 😭
37 Replies
JochCool
JochCool12mo ago
You're right, using await immediately after getting a task object does not make that code asynchronous. That code at the end is almost correct, but I think it should be like this:
C#
static async Task Main()
{
Task task = someTask();
Console.WriteLine(1);
await task;
}

static async Task someTask()
{
// Do something
await someOtherTask();
// Do something else
Console.WriteLine(2);
}
C#
static async Task Main()
{
Task task = someTask();
Console.WriteLine(1);
await task;
}

static async Task someTask()
{
// Do something
await someOtherTask();
// Do something else
Console.WriteLine(2);
}
This way, the 1 will be printed before awaiting, so it happens at the same time as the other task, making it asynchronous.
Blank
BlankOP12mo ago
So is it only truly asynchronous when used the way I wrote in the first code block? If, say, in a winforms application, in an async button click event, I make it await a long task, will the UI block? If not, why?
JochCool
JochCool12mo ago
I haven't worked much with WinForms, but if I recall correctly, it never awaits your event handlers. So the UI can be processed asynchronously while the task is busy.
Blank
BlankOP12mo ago
Oh now I see But if its like that, then why can't we use blocking code in the event handlers
mtreit
mtreit12mo ago
This discussion is mis-using the term asyncrhonous to mean concurrent I think.
Blank
BlankOP12mo ago
How are they different?
JochCool
JochCool12mo ago
Oh, yeah I may have messed up the terminology
mtreit
mtreit12mo ago
async means the original thread can do other work while the async operation is in flight. concurrent means two things are in progress at the same time.
Blank
BlankOP12mo ago
So is this assumption correct?
var task1 = sometask();
// Do something else
var result = await task1;
var task1 = sometask();
// Do something else
var result = await task1;
mtreit
mtreit12mo ago
Both are async. The second version is logically sequential. The first version is logically concurrent.
Blank
BlankOP12mo ago
When we await a task, it pauses the current function (and it can't do anything else). isn't this what blocking is?
mtreit
mtreit12mo ago
No This is something a lot of people struggle with. When you await, the function is "logically blocking" meaning that the next line of code doesn't run until the async operation completes. But it's not actually blocking a thread. The thread that the original await was running on can be used to do more work while the async operation is in progress. For instance, it gets returned to the thread pool in a web server to handle other requests. Or it's the UI thread in a UI application and it can process other UI events to repaint the window or whatever. Eventually, the async operation completes. Now the code after the await is scheduled to run, but potentially on some completely different thread than the original one. The fact that the original thread was released to go do other stuff while the async operation was in flight is why we say async is non-blocking.
Blank
BlankOP12mo ago
Makes things much clear
mtreit
mtreit12mo ago
When you await something, the async machinery wires up a continuation that will get run eventually when the async operation finishes. It's all part of the async state machine that is used. If you are interested there are detailed blog posts that go into very explicit detail about how this all works. But if you just want to use async, hopefully what I explained will clarify what's happening at a high level.
mtreit
mtreit12mo ago
Also if you want more material on this, I did a video on this topic: https://youtu.be/8lUs9ukVrFY
C# Community Discord
YouTube
Solution1: Threads, Tasks and more with Mike Treit
This presentation recaps some of the basics of writing code that makes use of threads, tasks and asynchronous features in C#. It is a modified version of a talk the author has given to his team at Microsoft. This is an intermediate level talk aimed at developers still learning how to write parallel and async code in C#.
Blank
BlankOP12mo ago
Yes, it was very helpful. I am still confused about this one thing. When we await a function, is it really needed that the function should use other asynchronous functions? Since its already in async state, we can use all synchronous functions?
mtreit
mtreit12mo ago
Anything that you call inside an async function that is a synchronous call blocks the thread the function is currently executing on. But if the synchronous calls are cheap it's fine. If they are doing network I/O or other stuff that is slow, those should also be async. An async method is like any other method until it gets to an await. Then it does the async thing and the thread it was running on can do other stuff. Then the continuation runs when the await finishes. Now we are back in the same state. The continuation runs like any other method until another await happens or it returns.
Blank
BlankOP12mo ago
So if the thread is doing something else, where does the async method gets executed?
mtreit
mtreit12mo ago
Sounds like you need to read $nothread
MODiX
MODiX12mo ago
There Is No Thread
This is an essential truth of async in its purest form: There is no thread.
Blank
BlankOP12mo ago
ou
mtreit
mtreit12mo ago
You said async method but I think you meant async operation.
Blank
BlankOP12mo ago
Yes
mtreit
mtreit12mo ago
Ultimately at some point you get to the point where the operating system is going to kick off an async operation at the hardware level. That usually involves something like a hardware interrupt that will interrupt the CPU when the async I/O is done and the OS then schedules that operation to be completed.
Blank
BlankOP12mo ago
makes sense
mtreit
mtreit12mo ago
That stuff is happening down in kernel mode (where there aren't really threads in the sense you tend to think of them) and that's why the user mode thread can be put to work to do other stuff until the kernel comes back and says "ok we're done."
Blank
BlankOP12mo ago
ah That is much better "The await keyword is used within an async method to temporarily suspend its execution and yield control back to the calling method until the awaited task is completed." What does it mean by yield control back to the calling method? By control I am understand something like the EIP pointer in x32.
mtreit
mtreit12mo ago
It just means that the method returns at that point. Returns a task to the caller. The calling method can choose to do whatever it wants with that task.
Blank
BlankOP12mo ago
Oh, it returns the task but doesn't go to the next instruction?
mtreit
mtreit12mo ago
Right
Blank
BlankOP12mo ago
understood
mtreit
mtreit12mo ago
Basically you can think of every await as ending the method and the code after the await is the start of a new method.
Blank
BlankOP12mo ago
Right
mtreit
mtreit12mo ago
What async and await does is hide that detail from you and make it look like one big method.
Blank
BlankOP12mo ago
That was all I could think of right now 😉 Thanks for helping!
Unknown User
Unknown User11mo ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX11mo ago
Use the /close command to mark a forum thread as answered

Did you find this page helpful?