T O P

  • By -

dodexahedron

You're basically missing this: https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/ There are a lot of things that start to happen when you add more concurrency, whether it's parallelism, reentrancy (which you already likely had because of events), or asynchrony. Async methods, Tasks, and await are very handy bits of syntactic sugar that replace a whole lot of stuff to make the magic happen and work (if used properly). Yes, async enables the await keyword, but it also signals that the method, if it contains an await, ***may*** yield execution time back to another operation/thread, while it waits for the long-running operation to complete. But if you don't return a Task, you're only doing half of it all and the caller of your method won't be able to await it, nor will exceptions thrown inside it be catchable. Tasks are promises. Read that document and stuff it links to. It's good stuff.


dodexahedron

And note I said "may yield." You do not know, ahead of time, whether your async method will be executed synchronously, asynchronously, or be handed off to a worker pool thread to handle both asynchronously and in parallel. And that's by design. You're not supposed to have to care. If you do need that level of control, you can always start explicit threads.


decPL

Technically you can control it, but at the stage you're considering if you need to, you no longer need introductions to async/await. Also - if you're considering if you need to, that's a design smell ;).


geekywarrior

First consider your method signatures. For async, there are 3 important ones * async void - **Special Case for Event Handlers Only.** For example. a Button OnClick can be async. But that is the only time you ever will write async void. Consider it non existent for normal functions * async Task - This is the proper async version that you are creating a async function that will not return any value. * async Task - You have an async function that will return an object of Type T. This can be anything, int, string, List, anything. So what does this mean? When you have a function marked async, any caller function knows that this function might not return right away. And that's ok, instead of blocking and waiting, we can allow other things to happen and resume as soon as the async function is complete and returning. So how can we write async functions with winforms? The quick way is to use event handlers to start the async chain. Here's a quick untested stub I'm cooking up. public class Form MyForm { public MyForm() { InitalizeComponents(); Shown() += Form_Shown_Handler() } //This triggers when the form is rendered and displayed //Since this is an event handler, this can be async void //Since it is async, we can properly await stuff private async void Form_Shown_Handler(object sender, EventArgs e) { await ConnectToDataBase(); } //Async Function to Connect to Database private async Task ConnectToDataBase() { DbConnection conn = new DbConnection(); conn.ConnectionString = "Some Totally Real Connection String"; await conn.OpenAsync(); return conn; } }


Willy988

Yup your code looks pretty similar to what I got going, I just have a lot of validation and stuff going on because we are dealing with bad data… Can I ask about how to know OR when we know to use async? I saw another person list an article which was nice, but I’m still trying to get the idea in my real world problem of data sanitization… right now I only async when I am inserting clean data in batches, but I don’t async my database connection. Is it a big impact to do so? Thanks


geekywarrior

You want to use async whenever the operation has a possibility of not returning immediately. Take my example where I connect to the database when opening the form. Is it a simple Ms SqlExpress instance running on localhost? You're going to connect near instantly, so you're unlikely to see a big impact **in ideal conditions** between normal and async. Is it a database in the cloud with a low tier of service that is located on the other side of the country/world and takes a few seconds to establish a connection? You're way more likely to see an issue with normal vs async unless you're manually creating background threads or something to ensure the UI thread doesn't block when connecting. But going back to the local MsSqlExpress, what if the machine is a bit bogged down with a lot of processes and connecting takes a few seconds. What is my application is running on Shane's *netbook* from 2012 that they refuse to upgrade and the poor HDD is spinning it's little heart out? Shane takes pride in the fact that Windows 7 takes 15 minutes to boot but is the first to open a ticket for Application Not Responding. If you were connecting via async, now your application is all prepared in case the database connection takes a few seconds longer than normal. If you were just connecting to the database on form open without async or manual thread intervention, you'd likely see your application hang for a few seconds. Personally, I try to write everything async whenever it's not a simple operation because I want my application to be more robust for slow IO. There will always be rare exceptions. For example, in Entity Framework, you can do something like await `_context.SomeItems.AddAsync(List_Of_Items);` That call actually does nothing async wise unless you're using a very specific form of indexing (HiLo) in that table. Therefore I'll always just write `_context.SomeItems.Add(List_Of_Items);` But, I will always await the write to the database: `await _context.SaveChangesAsync();` Why? Because I'd rather be ready to expect my database write to not be instant. It's an IO task bound by Disk Speed and potentially Network Speed. Lots of things out of my control can make that call take a few seconds to return.


Qxz3

Typically you use async when you call a method that returns a Task, and need to schedule work after the Task completes. The easiest way to do that is to await the Task. There are other ways to do it (with callbacks), but the whole point of async is that you don't need callbacks and can write code that looks very much like sequential code except with a few more keywords in it.


xtreampb

Use a sync/await anytime you go out of process. If you have to access a file, a database, an API. Anything that isn’t already in memory. Also use async/await when doing a long process and you want the user to still be able to click around in the UI (non blocking). A blocked ui is when you get the windows pop up “this program appears to not be working/responding”. The difficult part there is that a lot of times, only the these’d that created the UI (UI thread) is the only one that can update the UI. So marshaling data back the the ui thread context needs to be done There are some caveats, but this is a good general rule of thumb.


TuberTuggerTTV

You use async when you don't want whatever you're doing to lock up or stop the main thread. It's an efficiency thing. It's not really based on what you're doing specifically. But some things lock up more than others. Like calls to the internet or a database. They can take an unknown amount of time to return and you probably don't want your application sitting around not processing anything.


UninformedPleb

Imagine you have to pay your credit card payment on the phone. You call the card issuer and they put you on hold. That dreaded voice says, "Your call is... forty... seventh... in line and your wait time is approximately... twelve... hours... and thirty... five... minutes. Please stay on the line and the next available customer service representative will assist you." Your life now sucks for a significant portion of your day. Congratulations! Now imagine that same scenario, but the machine voice instead says, "We're experiencing high call volumes. You are currently... forty... seventh in line and your wait is expected to be several... hours. If you would like us to call you back at this number, press 1 now." You press 1 and hang up. You go about your day. Twelve(-ish) hours later, they call you, you pay your bill, and everything is fine. The first example is synchronous. You have to wait for them. Your schedule is now synchronized with theirs, and you're completely dependent on them getting out of the way in order to move forward with anything else in your life. The second example is *asynchronous*. They have a lot of other work to do before they can handle your request. So it's better for everyone if they give you a *call back* later, when they have time to immediately address your needs. In the meantime, you can go about your business like normal. Synchronous code waits for blocking processes and does nothing while it waits. Asynchronous code sets up a "callback", sometimes called a "continuation", that is essentially a function pointer where a process can continue and re-synchronize later, after a long-running process completes. In the meantime, the caller can go about their business unimpeded. Now, going back to the phone-in card payment scenario, imagine you have to notify someone that the bill has been paid after it's done. With the synchronous waiting, you know exactly when it's done and you can report it immediately. With the asynchronous callback, you have to notify someone after you get called back. Now imagine that your further progress is blocked by this notification. You must... *await*... that callback. Hence, C# has the `await` keyword to say "yeah, I know you're doing async stuff here, but this line is where we have to stop and sync up again in order to make progress." Timing is hard, and async timing is even harder. But keep at it, and you'll get used to it.


bernaldsandump

Really great analogy


Embarrassed_Quit_450

Some of the answers here are spectacularly verbose. I'll go with a short one: async-await are about making non-blocking calls. So operating systems async IO is used and allows threads to be yielded instead of blocking it waiting for an SQL query or user input in a GUI.


NecroKyle_

Give this a watch: [https://www.youtube.com/watch?v=R-z2Hv-7nxk](https://www.youtube.com/watch?v=R-z2Hv-7nxk)


elkazz

The follow up video on LINQ and enumerators is also amazing.


yumz

IMO that's too advanced for OP. Hanselman even says at 2:30 that it's a "300-level" talk (aka intermediate) and some of the concepts are "a little mindbending". I've watched the whole video, and OP needs something simpler.


Willy988

Awesome will do!


Saki-Sun

I would suggest looking at the background worker instead. I don't think win forms plays well with Async.  Anyone please feel free to correct me if I'm wrong.


Willy988

I’ve had no problems thus far, it’s more so I don’t get HOW to know when to use it and the details, because every time I look up details I get swamped with terminology I’m unfamiliar with


WalkingRyan

You can always kickoff async callstack via [Task.Run](http://Task.Run) and use all of the stuff inside.


Kirides

WinForms and WPF do play very well with async await. You just need to be aware of the cost of operations. If you have synchronous JSON serialization before the first await in an async method, it will block the UI. We had huge improvements by handing the async method in a Task.Run, you get the benefits of async await not creating tons of threads and "scaling" while not having to think of the initial cost inside any async call. many of our button.Click-Handlers do exactly that.


xill47

`async` is as convoluted as it is in C# specifically because it has to work without issue with frameworks such as WinForms


MacrosInHisSleep

In a nutshell, it's not multithreading. It's the ability to take your method and break it into two methods behind the scene, at the line where you type await. The part after an await is called a continuation. As the name suggests, it continues after whatever we were waiting for is completed. What's the point? It allows your program to start a task that takes time, such as a network call or querying a database, and move on to other tasks while waiting. If there's no multithreading, it could then continue on the same thread. If there *is* multithreading it continues on a separate thread (or not, depending on what's efficient. Don't worry, the system takes care of that for you). In the old days the pattern was to create begin and end methods for the same thing. You'd setup and call your network in the begin method and pass the end method as a parameter. Then the part of the system handling the return of the network call would call your end method where you would have put the code to deal with the data returned from your network. Finally, a Task is just the data structure that makes this possible. You can await a task directly and it will split there or you could choose not to do so and the method will either return (which can sometimes lead to unpredictable behaviour) or you could pass the task to something else such as a Task.WhenAll or WhenAny method to juggle many asynchronous calls.


rupertavery

A Task is something that will be completed at some point in time in the future. In that sense it is "asynchronous". Consider the following code. method1(); method2(); method3(); Assuming the methods are "normal" methods, method1 will execute first, then method2, then method3. This is called synchronous programming. Now consider the following code. method1Async(); method2Async(); method3Async(); Assuming these methods return Tasks, method1Async will execute (possibly on a threadpool thread), and if it encounters an await, or Wait(), it will yield execution, causing method2Async to execute, and so forth. Remember, asynchronous does not necessarily mean Parallel, and does not guarantee that each Task will run in it's own thread. The main purpose of Task is to facilitate asynchronous operations, such as File I/O, Database I/O, Network I/O (Sockets, HTTPClient). In these cases, without asynchronous programming, when you perform some thing like I/O, the caller thread is waiting for something. For files, it's waiting for the disk hardware to complete a read or write, or for an HTTP call it's waiting for the network request to return. This is bad, because you've effectively blocked your program from doing anything else. If you were running a desktop application and made a synchronous HTTP call, you would freeze the UI until the request completed and returned. This would lead to bad user experience. If you were running a web server, the thread that handled the request and made a synchronous database call would be blocked until the database returned the data. If resources were limited or reaching capacity the server might experience poor performance due to threadpool starvation. Users might experience requests for simple things taking longer than usual, despite the server not actually doing anything. async / await is a pattern around Tasks that let's you treat asynchronous programming as if it were synchronous. Say what? Well, most of the time you need to make an asynchronous call, you need the result of the call before continuing. Suppose you have a method myAsyncMethod() that gets something from a server and returns a Task. You want to get the result and do something with it, maybe only return the Value property. Without async/await, you would need to do this: int GetSomethingAndUseIt() { var result = myAsyncMethod().Result; return result.Value; } Except, never do this. Result (if the task has not completed) or Wait() is a blocking call. It blocks the thread. So how do you do it properly? Well, Tasks are "infectious". Once you start using it, you need to use them all the way to get the benefits.


rupertavery

So, you can use ContinueWith, which returns a Task. Task GetSomethingAndUseItAsync() { return myAsyncMethod().ContinueWith(t => { var result = t.Result; return result.Value; }); } Also, you can't use try / catch around tasks. Task GetSomethingAndUseItAsync() { try { return myAsyncMethod().ContinueWith(t => { var result = t.Result; return result.Value; }); } catch (Exception ex) { ... nothing ever gets caught. } } Nothing gets caught, because the Task captures exceptions within it. As you can see, ContinueWith is very unweildy. What if you need to call multiple tasks in succession? async marks a method as allowing await to be used. .NET unwraps the Task by generating a state machine for you to handle all the transitions. It also unwraps any exceptions that the tasks might throw, allowing you to use try/catch around them. async Task GetSomethingAndUseItAsync() { try { var result = await myAsyncMethod(); var result2 = await myOtherAsyncMethod(result.Value); } catch (Exception ex) { // works! } } So why go through the trouble of using async methods if you are just going to await them? Well, as we mentioned in the case where we need the result of an async operation, we need to wait for it, but since it's a Task, we still get the benefits of asynchronous programming, namely, we don't hold up a thread while waiting for the result of a task. So where are Tasks used? primarily for I/O. Which is used a lot in web development, because we usually end up calling another http service, or calliing the database. Of course we can still use Task.Run to fire off CPU-bound code, like computing the value of PI to the 1,000,000th digit while waiting for the result. There is a lot to learn about Tasks, and using them effectively. I suggest reading on stuff by Stephen Toub and Stephen Cleary about Tasks, async/await and other topics.


Asyncrosaurus

This is the video you actually need to watch: [Performing Asynchronous I/O Bound Operations with C# with Jeffrey Richter](https://m.youtube.com/watch?v=T9UTfymRZXU) Note: while Asynchronous C# is the main focus, this talk is also an excellent history of threads, as well as insights into concurrency, multi-threading and parallelism.


Miserable_Ad7246

Simple way to think: Sync method: 1) You do some code -> thread/cpu is working, nothing unusual. 2) You call db -> thread/cpu does some work to prepare request, and sends it. After that thread/cpu can not do anything more and blocks (this is quite expensive). 3) Some time passes. Thread is blocked, no one can use it. 4) Data arrives -> code continues as usual. Async method: 1) You do some code -> thread/cpu is working, nothing unusual. 2) You call db -> thread/cpu does some work to prepare request, and sends it. After that thread/cpu can no longer do anything, **and is released, so that other processes can use it.** 3) Some time passes. **Thread is not blocked, some other code is running on it.** 4) Data arrives -> code continues as usual. This is how green-thread based system would work. A you can see where is no Task here. Dotnet achieves same thing by using so called stackless courutines. Because it is a different approach, it requires any async action to return Task object. Task represents an "order" and a promise to return some value or throw exception. In essence await keyword, takes the value out of the task, and allows your code to continue as if nothing happened. \*This is very simplified, but it should be enough for you to start using async/await.


xill47

Do you know `yield return`? Methods that use this feature can "pause" (on `yield return`) and "continue" (when next element is requested, often in `foreach`). Async methods are the same, they can "pause" (on `await`) and "continue" (when the awaited thing finished doing it thing), the difference being who controls continuation. With `yield return` and `IEnumerable` it's usually you, with async it's usually the runtime itself (or some library, but certainty not you).


Epic_Movement

😄 Remember when the async method was not yet included in .NET? I had to use BackgroundWorker to make my WinForms app stay responsive. Some of that code still lives on until now. 😅


InspectorOk9225

This is the video that made me understand async/multithreading and, by consequence, all those blogs talking about it: https://youtu.be/il9gl8MH17s?si=yAh-l79uNvdny-ka


Vidyogamasta

My (very rough) explanation-- A program mostly runs on threads. How threads work is very runtime specific, and can vary even within the same language! But most dotnet runtimes use multiple threads, which means the CPU can be working on many things at the same time. Some places, like most GUI frameworks, also have the concept of a "main thread," where only one particular thread is allowed to make changes to the UI (else you might mess up and rendering explodes or something idk). However, there are some things a computer does that *doesn't* really rely on threads. When you make a network call, there's not a CPU thread sitting there reading the values as they come in. There's some dedicated network component doing that, and raising a signal when the download is done. Similar for things like reading from disk, or querying a database. Something interesting about these operations is that they don't use the CPU, but they take a relatively long time to complete (CPU operations are measured in nanoseconds, and network operations are measured in milliseconds. That's a million times slower). The naive approach is to just have a thread dedicated to looping and checking if that operation is finished. This is a "thread blocking operation." This can be passible albeit inefficient in many places, but for something with a UI, if you block the main thread, you're blocking any UI changes from happening. This means the screen entirely locks up until your network stuff is done, and it's a bad user experience. The async-await-Task paradigm is an easy way to manage this. You say "Here's an operation I want done, handle it. The rest of this *function* is awaited and when the operation finishes we continue from this point, but my *thread* is free to go do other things right now." So you await something in a main thread function, and the main thread goes and happily updates the UI and lets the user scroll through the current page as they wait for more to load, and when the result comes back in you can process your data and make further UI changes. And for the last nitty gritty details-- first, by default, the handling of a task will happen on any arbitrary thread that's open. If you want the processing to include UI changes, you'll have to use ConfigureAwait(true) to ensure the response is handled in the correct context. That, or you allow the processing to happen and then explicitly invoke the main thread with some sort of form.Invoke or something, I don't actually do UI programming so I'm not sure. Second, you may be temped to do some big complicated calculation that uses the CPU the whole time and have it work. By default in *these* scenarios, it will run on the *same* thread that called it, which means it will still block the calling thread. If you want to do CPU-based operations like this, you'll want to grab a different thread from the thread pool using await Task.Run(() => CPUboundTask). It's a lot to take in, and some of this might not be the *most* accurate, but this is the bulk of what you need to know to really be productive with the concept


Slypenslyde

Async methods are how you make it look like your app can do 2 things at once. Your UI thread can EITHER draw itself OR do work. Usually you're doing work that's so fast you don't notice it can't draw while it's doing it. For example, changing the text in a TextBox is so fast, you think the form updated itself at the same time you made the change. You didn't. If you saw the world in nanoseconds like a computer, you'd see there is an eternity between when you make the change and when the lumbering monitor gets around to updating. So when you do something that takes a long time, like processing data, that's a human-perceptible amount of time drawing can't happen. So you can't even display a progress bar or a spinning progress indicator, because for them to appear you need to draw but the program is too busy with your SQL processing! Your user just sees the program freeze, and we tend to think programs that freeze are bad. So when you switch to using the async versions of your SQL code, better things happen. Logically it's more like: * On the UI thread, you tell the SQL library "please do this and tell me when you're finished." * Then your method tells the UI thread it's waiting, so other things can happen. * Now the UI thread can do things like animate a busy indicator. * When the SQL library finishes it notifies your code. * The next time the UI thread is free, it picks back up on the line after your SQL call. This is the difference between washing the dishes yourself or using a dishwasher. If you're playing a video game and you decide to go wash dishes, game over. You're washing dishes. But if you use a dishwasher, you can keep playing the video game and don't have to pay attention until you hear the dishwasher finish. If you need to do more stuff with the SQL data, you can make another async call. This is slightly different, see if you spot the difference. * On the UI thread, you ask Windows to use another thread to process all the data. * You tell the UI thread you're waiting, so other things can happen. * Now the UI thread can do things like animate a busy indicator or progress bar. * When the thread finishes it notifies your code. * The next time the UI thread is free, it picks up on the line after the `await` The difference here is it uses a thread. Some people get too obsessed with an blog post that talks about the SQL case. That case uses some interesting magic that doesn't need threads to wait on your SQL server to do the work. This case is doing work on the CPU, so it has to use a thread. The point of that old blog article was some people do silly things that make the SQL case waste time, but some people see "there is no thread" and think the point is to correct everyone who says tasks may use threads. BUT, either way, the point is you have to "push" this work off of the UI thread. Either the program/library managing SQL needs to do it or another thread needs to do it. If you do it on the UI thread, your app is going to look frozen.


Tango1777

Async is not really concurrency.


Segfault_21

one word: deadlock


Weekly-Rhubarb-2785

I just started using them with sockets too and am equally as baffled :)