C# Async await deadlock problem gone in .NetCore? - c#

In .NetFramework there was a high risk of a deadlock occuring when synchronizing to the synchronization context using:
var result = asyncMethod().Result;
var result = asyncMethod().GetAwaiter().GetResult();
instead of
var result = await asyncMethod();
(read Stephen Cleary blogpost for more info)
Since the synchronization context has been removed in .NetCore. Does this mean that the above methods are now safe to use?

Yes and no. It's true that there's no synchronization context in .NET Core, and thereby, one of the major sources of deadlock issues has been eliminated. However, this doesn't mean that deadlocks are totally impossible. Regardless, you should not let good programming practices slide, just because it may not be a big issue in one circumstance any more. ASP.NET Core, in particular, is fully async, so there is no reason to ever use a sync version of a method or simply block on an async task. Use await as you always would and should.

You Can Block on Async Code - But You Shouldn’t
The first and most obvious consequence is that there’s no context captured by await. This means that blocking on asynchronous code won’t cause a deadlock. You can use Task.GetAwaiter().GetResult() (or Task.Wait or Task.Result) without fear of deadlock.
However, you shouldn’t. Because the moment you block on asynchronous code, you’re giving up every benefit of asynchronous code in the first place. The enhanced scalability of asynchronous handlers is nullified as soon as you block a thread.
There were a couple of scenarios in (legacy) ASP.NET where blocking was unfortunately necessary: ASP.NET MVC filters and child actions. However, in ASP.NET Core, the entire pipeline is fully asynchronous; both filters and view components execute asynchronously.
In conclusion, ideally you should strive to use async all the way; but if your code needs to, it can block without danger.
-Extract from blogpost by Stephen Cleary
Credit to GSerg for finding the post
However, you might encounter thread pool starvation
http://labs.criteo.com/2018/10/net-threadpool-starvation-and-how-queuing-makes-it-worse/

Related

What am I losing between Task.Run(() => MyTask).Result, await MyTask and MyTask.Result?

I'm not sure if I'm even asking the question correctly, so bear with me; here's what I'm dealing with:
In my MVC4 project (targetting .Net 4.5.1) If I do await SomeAsyncMethod(...), then the task completes in the background but appears to never return. I believe this has something to do with the thread being returned to the pool and then resuming on a different thread. The workaround I've been using is to use Thread.Run(() => SomeTask).Result;.
So, I find myself having to do Thread.Run(() => SomeAsyncMethod).Result; a lot in my MVC projects lest I end up with deadlocks. Isn't this just another syntax for running the Task synchronously? I'm not sure if this is a limitation of MVC 4 (versus MVC 5) or if that's just how the api works. Am I essentially gaining nothing in terms of asynchronicity by doing this?
We've written a small library here where all of the operations are async Task<T> and it is in a separate assembly, so at least we can use it "properly" elsewhere (e.g. a window phone app), but this MVC 4 project is a consumer of said library, and it feels like we're basically stepping around the benefits of async/await in order to avoid deadlocks, so I'm looking for help in seeing the bigger picture here. It would help to better understand what I'm gaining by consuming asynchronous tasks in a synchronous mannger (if anything), what I'm losing, if there's a solution that gives me back the ability to await these tasks without deadlocking, and whether or not the situation is different between MVC 4 and MVC 5+
TIA
In my MVC4 project (targetting .Net 4.5.1) If I do await SomeAsyncMethod(...), then the task completes in the background but appears to never return.
This is almost certainly due to one of two things. Either:
Code further up the call stack is calling Result or Wait on a task. This will cause a deadlock in ASP.NET. The correct solution is to replace Result/Wait with await. I have more details on my blog.
The httpRuntime#targetFramework is not set to 4.5 or higher in your web.config. This is a common scenario for ASP.NET projects upgraded from an earlier version; you need to explicitly set this value for await to work correctly. There are more details in this blog post.
So, I find myself having to do Thread.Run(() => SomeAsyncMethod).Result; a lot in my MVC projects lest I end up with deadlocks. Isn't this just another syntax for running the Task synchronously?
Pretty much. What actually happens is that SomeAsyncMethod is run on a thread pool thread and then the request thread is blocked until that method is complete.
Am I essentially gaining nothing in terms of asynchronicity by doing this?
Correct. In fact, you're netting a negative benefit.
The whole point of asynchrony on the server side is to increase scalability by freeing up the request threads whenever they aren't needed. The Task.Run(..).Result technique not only prevents the request thread from being freed, it also uses other threads to do the actual work. So it's worse than just doing it all synchronously.
ASP .NET MVC 4 should be aware of the async keyword on Actions and should correctly handle resuming the request when using the await keyword. Are you sure the Action in question that uses await returns a Task and doesn't try to return T itself?
This is handled by ASP .NET MVC using a SynchronizationContext to ensure that the request is resumed correctly after awaiting even if it is on a different thread.
And yes, if you just call .Result, it's blocking the calling thread until the Task completes and you end up using (potentially) two threads for the same request without any benefit.
http://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4
Addition to #Stephen's answer, my 2 cents:
I believe this has something to do with the thread being returned to the pool and then resuming on a different thread.
Edit:
No, it all happens on single thread(usually UI thread, in case of MVC it's thread allocated for the request). Async await work on Message pump which is an infinite loop running on single thread. Each await puts a message on message pump and checks if it finished.
Above is not exactly applied for Asp.net. See #Jeff's comments below.
=========================================================
One rule of Async framework, If it's Async, keep it Async all the way.
Creating synchronous wrapper over Async method often results in blocking Main threads where Main thread and Task thread keep on waiting for each other to respond.

Why does an async single task run faster than a normal single task?

I have a method which has just one task to do and has to wait for that task to complete:
public async Task<JsonResult> GetAllAsync()
{
var result = await this.GetAllDBAsync();
return Json(result, JsonRequestBehavior.AllowGet);
}
public async Task<List<TblSubjectSubset>> GetAllDBAsync()
{
return await model.TblSubjectSubsets.ToListAsync();
}
It is significantly faster than when I run it without async-await.
We know
The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the
method is active
According to this link: https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads. What is the reason for being faster when we don't have another thread to handle the job?
"Asynchronous" does not mean "faster."
"Asynchronous" means "performs its operation in a way that it does not require a thread for the duration of the operation, thus allowing that thread to be used for other work."
In this case, you're testing a single request. The asynchronous request will "yield" its thread to the ASP.NET thread pool... which has no other use for it, since there are no other requests.
I fully expect asynchronous handlers to run slower than synchronous handlers. This is for a variety of reasons: there's the overhead of the async/await state machine, and extra work when the task completes to have its thread enter the request context. Besides this, the Win32 API layer is still heavily optimized for synchronous calls (expect this to change gradually over the next decade or so).
So, why use asynchronous handlers then?
For scalability reasons.
Consider an ASP.NET server that is serving more than one request - hundreds or thousands of requests instead of a single one. In that case, ASP.NET will be very grateful for the thread returned to it during its request processing. It can immediately use that thread to handle other requests. Asynchronous requests allow ASP.NET to handle more requests with fewer threads.
This is assuming your backend can scale, of course. If every request has to hit a single SQL Server, then your scalability bottleneck will probably be your database, not your web server.
But if your situation calls for it, asynchronous code can be a great boost to your web server scalability.
For more information, see my article on async ASP.NET.
I agree with Orbittman when he mentions the overhead involved in the application architecture. It doesn't make for a very good benchmark premise since you can't be sure if the degradation can indeed be solely attributed to the async vs non-async calls.
I've created a really simple benchmark to get a rough comparison between an async and a synchronous call and async loses every time in the overall timing actually, though the data gathering section always seems to end up the same. Have a look: https://gist.github.com/mattGuima/25cb7893616d6baaf970
Having said that, the same thought regarding the architecture applies. Frameworks handle async calls differently: Async and await - difference between console, Windows Forms and ASP.NET
The main thing to remember is to never confuse async with performance gain, because it is completely unrelated and most often it will result on no gain at all, specially with CPU-bound code. Look at the Parallel library for that instead.
Async await is not the silver bullet that some people think it is and in your example is not required. If you were processing the result of the awaitable operation after you received it then you would be able to return a task and continue on the calling thread. You wouldn't have to then wait for the rest of the operation to complete. You would be correct to remove the async/await in the above code.
It's not really possible to answer the question without seeing the calling code either as it depends on what the context is trying to trying to do with the response. What you are getting back is not just a Task but a task in the context of the method that will continue when complete. See http://codeblog.jonskeet.uk/category/eduasync/ for much better information regarding the inner workings of async/await.
Lastly I would question your timings as with an Ajax request to a database and back there other areas with potentially greater latency, such as the HTTP request and response and the DB connection itself. I assume that you're using an ORM and that alone can cause an overhead. I wonder whether it's the async/await that is the problem.

ConfigureAwait(false) on Top Level Requests

I'm trying to figure out if ConfigureAwait(false) should be used on top level requests. Reading this post from a somewhat authority of the subject:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
...he recommends something like this:
public async Task<JsonResult> MyControllerAction(...)
{
try
{
var report = await _adapter.GetReportAsync();
return Json(report, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json("myerror", JsonRequestBehavior.AllowGet); // really slow without configure await
}
}
public async Task<TodaysActivityRawSummary> GetReportAsync()
{
var data = await GetData().ConfigureAwait(false);
return data
}
...it says to using ConfigureAwait(false) on every await except the top level call. However when doing this my exception takes several seconds to return to the caller vs. using it and it and having it come back right away.
What is the best practice for MVC controller actions that call async methods? Should I use ConfigureAwait in the controller itself or just in the service calls that use awaits to request data, etc.? If I don't use it on the top level call, waiting several seconds for the exception seems problematic. I don't need the HttpContext and I've seen other posts that said always use ConfigureAwait(false) if you don't need the context.
Update:
I was missing ConfigureAwait(false) somewhere in my chain of calls which was causing the exception to not be returned right away. However the question still remains as posted as to whether or not ConfigureAwait(false) should be used at the top level.
Is it a high traffic website? One possible explanation might be that you're experiencing ThreadPoolstarvation when you are not using ConfigureAwait(false). Without ConfigureAwait(false), the await continuation is queued via AspNetSynchronizationContext.Post, which implementation boils down to this:
Task newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action));
_lastScheduledTask = newTask; // the newly-created task is now the last one
Here, ContinueWith is used without TaskContinuationOptions.ExecuteSynchronously (I'd speculate, to make continuations truly asynchronous and reduce a chance for low stack conditions). Thus, it acquires a vacant thread from ThreadPool to execute the continuation on. In theory, it might happen to be the same thread where the antecedent task for await has finished, but most likely it'd be a different thread.
At this point, if ASP.NET thread pool is starving (or has to grow to accommodate a new thread request), you might be experiencing a delay. It's worth mentioned that the thread pool consists of two sub-pools: IOCP threads and worker threads (check this and this for some extra details). Your GetReportAsync operations is likely to complete on an IOCP thread sub-pool, which doesn't seem to be starving. OTOH, the ContinueWith continuation runs on a worker thread sub-pool, which appears to be starving in your case.
This is not going to happen in case ConfigureAwait(false) is used all the way through. In that case, all await continuations will run synchronously on the same threads the corresponding antecedent tasks have ended, be it either IOCP or worker threads.
You can compare the thread usage for both scenarios, with and without ConfigureAwait(false). I'd expect this number to be larger when ConfigureAwait(false) isn't used:
catch (Exception ex)
{
Log("Total number of threads in use={0}",
Process.GetCurrentProcess().Threads.Count);
return Json("myerror", JsonRequestBehavior.AllowGet); // really slow without configure await
}
You can also try increasing the size of the ASP.NET thread pool (for diagnostics purpose, rather than an ultimate solution), to see if the described scenario is indeed the case here:
<configuration>
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="6000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="6000" />
</system.web>
</configuration>
Updated to address the comments:
I realized I was missing a ContinueAwait somewhere in my chain. Now it
works fine when throwing an exception even when the top level doesn't
use ConfigureAwait(false).
This suggests that your code or a 3rd party library in use might be using blocking constructs (Task.Result, Task.Wait, WaitHandle.WaitOne, perhaps with some added timeout logic). Have you looked for those? Try the Task.Run suggestion from the bottom of this update. Besides, I'd still do the thread count diagnostics to rule out thread pool starvation/stuttering.
So are you saying that if I DO use ContinueAwait even at the top level
I lose the whole benefit of the async?
No, I'm not saying that. The whole point of async is to avoid blocking threads while waiting for something, and that goal is achieved regardless of the added value of ContinueAwait(false).
What I'm saying is that not using ConfigureAwait(false) might introduce redundant context switching (what usually means thread switching), which might be a problem in ASP.NET if thread pool is working at its capacity. Nevertheless, a redundant thread switch is still better than a blocked thread, in terms of the server scalability.
In all fairness, using ContinueAwait(false) might also cause redundant context switching, especially if it's used inconsistently across the chain of calls.
That said, ContinueAwait(false) is also often misused as a remedy against deadlocks caused by blocking on asynchronous code. That's why I suggested above to look for those blocking construct across all code base.
However the question still remains as posted as to whether or not
ConfigureAwait(false) should be used at the top level.
I hope Stephen Cleary could elaborate better on this, by here's my thoughts.
There's always some "super-top level" code that invokes your top-level code. E.g., in case of a UI app, it's the framework code which invokes an async void event handler. In case of ASP.NET, it's the asynchronous controller's BeginExecute. It is the responsibility of that super-top level code to make sure that, once your async task has completed, the continuations (if any) run on the correct synchronization context. It is not the responsibility of the code of your task. E.g., there might be no continuations at all, like with a fire-and-forget async void event handler; why would you care to restore the context inside such handler?
Thus, inside your top-level methods, if you don't care about the context for await continuations, do use ConfigureAwait(false) as soon as you can.
Moreover, if you're using a 3rd party library which is known to be context agnostic but still might be using ConfigureAwait(false) inconsistently, you may want to wrap the call with Task.Run or something like WithNoContext. You'd do that to get the chain of the async calls off the context, in advance:
var report = await Task.Run(() =>
_adapter.GetReportAsync()).ConfigureAwait(false);
return Json(report, JsonRequestBehavior.AllowGet);
This would introduce one extra thread switch, but might save you a lot more of those if ConfigureAwait(false) is used inconsistently inside GetReportAsync or any of its child calls. It'd also serve as a workaround for potential deadlocks caused by those blocking constructs inside the call chain (if any).
Note however, in ASP.NET HttpContext.Current is not the only static property which is flowed with AspNetSynchronizationContext. E.g., there's also Thread.CurrentThread.CurrentCulture. Make sure you really don't care about loosing the context.
Updated to address the comment:
For brownie points, maybe you can explain the effects of
ConfigureAwait(false)... What context isn't preserved.. Is it just the
HttpContext or the local variables of the class object, etc.?
All local variables of an async method are preserved across await, as well as the implicit this reference - by design. They actually gets captured into a compiler-generated async state machine structure, so technically they don't reside on the current thread's stack. In a way, it's similar to how a C# delegate captures local variables. In fact, an await continuation callback is itself a delegate passed to ICriticalNotifyCompletion.UnsafeOnCompleted (implemented by the object being awaited; for Task, it's TaskAwaiter; with ConfigureAwait, it's ConfiguredTaskAwaitable).
OTOH, most of the global state (static/TLS variables, static class properties) is not automatically flowed across awaits. What does get flowed depends on a particular synchronization context. In the absence of one (or when ConfigureAwait(false) is used), the only global state preserved with is what gets flowed by ExecutionContext. Microsoft's Stephen Toub has a great post on that: "ExecutionContext vs SynchronizationContext". He mentions SecurityContext and Thread.CurrentPrincipal, which is crucial for security. Other than that, I'm not aware of any officially documented and complete list of global state properties flowed by ExecutionContext.
You could peek into ExecutionContext.Capture source to learn more about what exactly gets flowed, but you shouldn't depend on this specific implementation. Instead, you can always create your own global state flow logic, using something like Stephen Cleary's AsyncLocal (or .NET 4.6 AsyncLocal<T>).
Or, to take it to the extreme, you could also ditch ContinueAwait altogether and create a custom awaiter, e.g. like this ContinueOnScope. That would allow to have precise control over what thread/context to continue on and what state to flow.
However the question still remains as posted as to whether or not ConfigureAwait(false) should be used at the top level.
The rule of thumb for ConfigureAwait(false) is to use it whenever the rest of your method doesn't need the context.
In ASP.NET, the "context" is not actually well-defined anywhere. It does include things like HttpContext.Current, user principal, and user culture.
So, the question really comes down to: "Does Controller.Json require the ASP.NET context?" It's certainly possible that Json doesn't care about the context (since it can write the current response from its own controller members), but OTOH it does do "formatting", which may require the user culture to be resumed.
I don't know whether Json requires the context, but it's not documented one way or the other, and in general I assume that any calls into ASP.NET code may depend on the context. So I would not use ConfigureAwait(false) at the top-level in my controller code, just to be on the safe side.

Set SynchronizationContext to null instead of using ConfigureAwait(false)

I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method. I can't control that async method (it uses async/await and does not use ConfigureAwait(false)), nor can I replace it.
The code executes in the context of an ASP .NET request, so to avoid deadlocks, here's what I've done:
var capturedContext = SynchronizationContext.Current;
try
{
// Wipe the sync context, so that the bad library code won't find it
// That way, we avoid the deadlock
SynchronizationContext.SetSynchronizationContext(null);
// Call the async method and wait for the result
var task = MyMethodAsync();
task.Wait();
// Return the result
return task.Result;
}
finally
{
// Restore the sync context
SynchronizationContext.SetSynchronizationContext(capturedContext);
}
Does this produce the same effect as if MyMethodAsync had used ConfigureAwait(false) on all of its await's? Are there some other problems with this approach that I'm overlooking?
(MyMethodAsync is completely unaware that it's being run in an ASP .NET context, it doesn't do any calls to HttpContext.Current or anything like that. It just does some async SQL calls, and the writer didn't put ConfigureAwait(false) on any of them)
I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method.
The library is wrong to expose a synchronous version. Just pretend the synchronous API doesn't exist.
so to avoid deadlocks
There shouldn't be any problems with deadlocks if you call an asynchronous method that uses async/await. If it doesn't use ConfigureAwait(false), then it's not as efficient as it could be, that's all. Deadlocks due to ConfigureAwait(false) only apply when you're trying to do sync-over-async (i.e., if you're calling the synchronous APIs from that library).
So, the easiest and simplest solution is to just ignore the synchronous APIs, which are incorrectly designed anyway:
return await MyMethodAsync();
Provided you wrap this technique in a suitably named static function, I think your suggest is significantly better than Task.Run, even if still the lesser of two evils.
Task.Run has a number of issues:
It is not clear why you are using it, you want to start a new task on a web server? This will be deleted by new developers fast if there are no comments. And then boom, difficult to diagnose production issues (deadlocks).
It starts on a new thread pool thread when it doesn't need to until it reaches its first await completed continuation.
It makes you block synchronously for the entire Task returning function, when from your description of the problem, the blocking is actually just part of the overall task. What is being encouraged here is longer blocking over async code, this is certainly not what you want.
If you use it multiple levels, you are multiplying the problem (with SetSynchronizationContext there's no harm in doing it more than once).
If it turns out that there was no blocking / deadlock where you thought there was, or it had been fixed, Task.Run now is introducing blocking over async, whereas SetSynchronizationContext will not cost you anything, in addition to the optimizations it makes by not resuming on the context constantly.
I also understand there is hesitance to make any recommendation given blocking on async code should be avoided at all costs, however you have made it clear you are aware of this and this is to fix a known case of this outside of your immediate control. I think the dogmatic attitude towards this topic is damaging to the .NET ecosystem.
Setting the SynchronizationContext to null seems hacky for me. Instead you can really delegate the work to threadpool. Use Task.Run..
var result = Task.Run(() => MyMethodAsync()).Result;
or
var result = Task.Run(async () => await MyMethodAsync()).Result;
This avoids the deadlock and eliminates the hacky code as well.

Is async and await exclusively for GUI-based asynchronous programming?

I've been reading about the new async and await operators in C# and tried to figure out in which circumstances they would possibly be useful to me. I studied several MSDN articles and here's what I read between the lines:
You can use async for Windows Forms and WPF event handlers, so they can perform lengthy tasks without blocking the UI thread while the bulk of the operation is being executed.
async void button1_Click(object sender, EventArgs e)
{
// even though this call takes a while, the UI thread will not block
// while it is executing, therefore allowing further event handlers to
// be invoked.
await SomeLengthyOperationAsync();
}
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
In other words, if you create a thread with an ordinary good old ThreadStart entry point (or a Console application with good old static int Main(string[] args)), then you cannot use async and await because at one point you would have to use await, and make the method that uses it async, and hence in the calling method you also have to use await and make that one async and so on. But once you reach the thread entry point (or Main()), there's no caller to which an await would yield control to.
So basically you cannot use async and await without having a GUI that uses the standard WinForms and WPF message loop. I guess all that makes indeed sense, since MSDN states that async programming does not mean multithreading, but using the UI thread's spare time instead; when using a console application or a thread with a user defined entry point, multithreading would be necessary to perform asynchronous operations (if not using a compatible message loop).
My question is, are these assumptions accurate?
So basically you cannot use async and await without having a GUI that uses the standard WinForms and WPF message loop.
That's absolutely not the case.
In Windows Forms and WPF, async/await has the handy property of coming back to the UI thread when the asynchronous operation you were awaiting has completed, but that doesn't mean that's the only purpose to it.
If an asynchronous method executes on a thread-pool thread - e.g. in a web service - then the continuation (the rest of the asynchronous method) will simply execute in any thread-pool thread, with the context (security etc) preserved appropriately. This is still really useful for keeping the number of threads down.
For example, suppose you have a high traffic web service which mostly proxies requests to other web services. It spends most of its time waiting for other things, whether that's due to network traffic or genuine time at another service (e.g. a datbase). You shouldn't need lots of threads for that - but with blocking calls, you naturally end up with a thread per request. With async/await, you'd end up with very few threads, because very few requests would actually need any work performed for them at any one point in time, even if there were a lot of requests "in flight".
The trouble is that async/await is most easily demonstrated with UI code, because everyone knows the pain of either using background threads properly or doing too much work in the UI thread. That doesn't mean it's the only place the feature is useful though - far from it.
Various server-side technologies (MVC and WCF for example) already have support for asynchronous methods, and I'd expect others to follow suit.
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
Not true - methods marked async just mean they can use await, but callers of those methods have no restrictions. If the method returns Task or Task<T> then they can use ContinueWith or anything else you could do with tasks in 4.0
A good non-UI example is MVC4 AsyncController.
Ultimately, async/await is mostly about getting the compiler rewriting so you can write what looks like synchronous code and avoid all the callbacks like you had to do before async/await was added. It also helps with the SynchronizationContext handling, useful for scenarios with thread affinity (UI frameworks, ASP.NET), but even without those, it's still useful. Main can always do DoStuffAsync().Wait(); for instance. :)
My question is, are these assumptions accurate?
No.
You can use async for Windows Forms and WPF event handlers, so they can perform lengthy tasks without blocking the UI thread while the bulk of the operation is being executed.
True. Also true for other UI applications including Silverlight and Windows Store.
And also true for ASP.NET. In this case, it's the HTTP request thread that is not blocked.
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
This is a best practice ("async all the way down"), but it's not strictly required. You can block on the result of an asynchronous operation; many people choose to do this in Console applications.
an ordinary good old ThreadStart entry point
Well... I do have to take issue with "ordinary good old". As I explain on my blog, Thread is pretty much the worst option you have for doing background operations.
I recommend you review my introduction to async and await, and follow up with the async / await FAQ.
async-await is only wrapper for Task class manipulations, which is part of so named Tasks Parallel Library - TPL(published before async-await auto code generation tech.)
So fact is you may not use any references to UI controls within async - await.
Typically async-await is powerfull tool for any web and server relations, loading resources, sql. It works with smart waiting data with alive UI.
Typically TPL application: from simple big size loop till multi stages parallel calculations in complex calculations based on shared data (ContinueWith and so on)

Categories

Resources