how extensively should the async/await pattern be used? - c#

I came across the following comment on SO:
"Also use of the async await pattern with newer versions of .Net will give the efficiencies closer to that of the event-driven architectures like NodeJS and Nginx"
I inherited a Web API app where basically all methods in all layers leverage the async/await pattern. The comment above about the performance of async/await is pretty compelling. Is it proper to implement async/await on all methods of all layers in a Web API app? Are there any scenarios where I should avoid await/async or be careful to not overuse it?

I recommend reading my intro to async on ASP.NET article.
Is it proper to implement async/await on all methods of all layers in a Web API app?
Yes. In fact, it's imperative. async really only works (in terms of providing the benefits you get from async) if you use it all the way. So, if your implementation calls another API asynchronously, then that method should be consumed asynchronously, etc., all the way up to your initial controller action.
In particular, you want to avoid sync-over-async antipatterns.
Are there any scenarios where I should avoid await/async or be careful to not overuse it?
Yes. You should avoid "fake async". This is the antipattern where a developer uses Task.Run (or similar) in order to get a task so they can "use async". It often looks like this:
int GetId() { ... }
Task<int> GetIdAsync() => Task.Run(() => GetId());
...
var id = await GetIdAsync(); // Look, I'm async! (not really)
In this case, the code is hurting your scalability rather than helping it.

Related

Asynchronous delegates: performance in modern .NET world

There is a legacy project. There are a lof of Asynchronous delegates and code like this:
IAsyncResult result = startDelegate.BeginInvoke(param1,
param2,
new AsyncCallback(CallbackMethod),
null);
or just completely parameterless calls
like
IAsyncResult result = startDelegate.BeginInvoke(CallbackMethod,null);
The main purpose of desired refactoring is: performance. Many places in the project has been optimized a lot and now it's time for async stuff.
From performance point of view: is there any sense to migrate from Async delegates calls to:
ThreadPool.QueueUserWorkItem for parametless calls
 BackgroundWorker to report progres to GUI (now GUI subcribes to events in async code)
Rewrite some parts to async await?
so, general question: how bad (or not bad) from performance point of view Async delegates in compare with 1)-3) above?
The main purpose of desired refactoring is: performance.
You almost certainly won't see noticeable performance gains from changing this. However, there are two major benefits for replacing Delegate.BeginInvoke calls:
Maintainability. async/await is the style of asynchronous programming that is most maintainable.
Portability. Last I checked, .NET Core doesn't support Delegate.BeginInvoke, so if you ever move from .NET Desktop Framework to .NET Core, you'll need to change this code. Side note: there are some pretty good performance benefits just from migrating to .NET Core.
If you do choose to remove the calls to BeginInvoke, I recommend using Task.Run. It's a modern solution.

Is Task.Run or TaskFactory.StartNew always inappropriate to use in async methods?

I've heard that the responsibility for threading should lie on the application and I shouldn't use Task.Run or maybe TaskFactory.StartNew in async methods.
However if I have a library that has methods that do quite heavy computation, then to free the threads that for example are accepting asp .net core http requests, couldn't I make the method async and make it run a long running task? Or this should be a sync method and the asp .net core application should be responsible to start the task?
At first, let's think why we need Asynchrony?
Asynchrony is needed either for scalability or offloading.
In case of Scalability, exposing async version of that call does nothing. Because you’re typically still consuming the same amount of resources you would have if you’d invoked it synchronously, even a bit more. But, Scalability is achieved by decreasing the amount of resources you use. And you are not decreasing resources by using Task.Run().
In case of Offloading, you can expose async wrappers of your sync methods. Because it can be very useful for responsiveness, as it allows you to offload long-running operations to a different thread. And in that way, you are getting some benefit from that async wrapper of your method.
Result:
Wrapping a synchronous method with a simple asynchronous façade does not yield any scalability benefits, but yields offloading benefits. But in such cases, by exposing only the synchronous method, you get some nice benefits. For example:
Surface area of your library is reduced.
Your users will know whether there are actually scalability benefits to using exposed asynchronous APIs
If both the synchronous method and an asynchronous wrapper around it are exposed, the developer is then faced with thinking they should invoke the asynchronous version for scalability(?) reasons, but in reality will actually be hurting their throughput by paying for the additional offloading overhead without the scalability benefits.
The source is Should I expose asynchronous wrappers for synchronous methods? by Stepen Toub. And I strongly recommend to you to read it.
Update:
Question in the comment:
Scalability is well explained in that article, with one example. Let's take into account Thread.Sleep. There are two possible ways to implement async version of that call:
public Task SleepAsync(int millisecondsTimeout)
{
return Task.Run(() => Sleep(millisecondsTimeout));
}
And another new implementation:
public Task SleepAsync(int millisecondsTimeout)
{
TaskCompletionSource<bool> tcs = null;
var t = new Timer(delegate { tcs.TrySetResult(true); }, null, –1, -1);
tcs = new TaskCompletionSource<bool>(t);
t.Change(millisecondsTimeout, -1);
return tcs.Task;
}
Both of these implementations provide the same basic behavior, both completing the returned task after the timeout has expired. However, from a scalability perspective, the latter is much more scalable. The former implementation consumes a thread from the thread pool for the duration of the wait time, whereas the latter simply relies on an efficient timer to signal the Task when the duration has expired.
So, in your case, just wrapping call with Task.Run won't be exposed for scalability, but offloading. But, user of that library is not aware of that.
User of your library, can just wrap that call with Task.Run himself. And I really, think he must do it.
Not exactly answering the question (I think the other answer is good enought for that), but to add some additional advice: Becareful with using Task.Run in a library which other people can use. It can cause unexpected Thread pool starvation for the library users. For example a developer is using a lot of third party libraries and all of them use Task.Run() and stuff. Now the developer tries to use Task.Run in his app too, but it slows down his app, because the thread pool is already used up by the third party libraries.
When you want to parallel stuff with Parallel.ForEach it is a different issue.

Pitfalls of wrapping callback async methods with Task async methods?

I'm creating a service layer for my WPF app that will wrap a web API client that uses Action<T> callbacks for it's asynchronous methods. Since I'm going to need to wrap the methods anyway, I was considering making my wrapper methods of my service layer conform to the new Task-based async pattern of .NET 4.5, rather than expose Action<T> callbacks.
I don't currently have a pressing need for Task-based async, but I also don't have any reason that I necessarily have to stay with the callbacks and wrapping seems easy enough (as described here) Backwards compatibility isn't an issue. That said, if there are any pitfalls to such Action<T> callbacks to Tasks wrapping, I'll just maintain the status quo.
I do not see any pitfalls with doing this, in fact it opens your application to allot more flexible scenarios. I would suggest you also look at converting some of your "call back" scenarios to a the observer pattern (see Reactive Extensions project by Microsoft) which, when combined with the Task-based pattern, is so much more powerful and flexible. And of course you will be able to use your new new Task-based pattern with the new async/await-pattern in C# 5.0!
Hope it helps.

Async calls chaining in Metro app

I am quite new to Metro dev and I only hope I will be able to express my question in an understandable way...
Actually I am porting a part of my old application to Metro. The logic part is a separated project (Portable Library) and it should serve to 1) the old WPF app and 2) the new Metro app. The basic logic is the same but some subsystems (for example file operations manager) must be coded differently - i.e. async way for Metro.
My question is: Do I have to rewrite the whole chain of methods caller-callee to the new async paradigm? Let's say I have a chain of 4 methods, starting by method A = Metro UI event async handler (it makes sense to me to code it as async void as it is the top fire&forget event), through the next 2 methods (B and C) placed in different layers of my application, down to the method D containing "await CreateFileAsync" method (made async by Microsoft).
Now: async CreateFileAsync method should be called with await. That forces me to make method D async too. To call method D from C and C from B and B from A - do I have to rewrite all A, B and C into the async-await style?
I can feel I am missing a deeper knowledge so I am trying to educate myself but concurrently I wanted to try my luck here...
Do I have to rewrite a big part of my code? Is any of my statements above wrong?
Many thanks in advance, Hans
I recommend that you do rewrite your portable library to be asynchronous. It's not as bad as it used to be; Microsoft worked very hard on async/await to make it as easy as possible to convert synchronous code to asynchronous. I expect that a whole lot of others will be doing the same in the near future, and R# will probably implement a "make async" rewriting.
There are non-obvious pitfalls when mixing synchronous and asynchronous code - see Stephen Toub's last blog post Should I expose synchronous wrappers for asynchronous methods? For this reason, I think it's just cleaner to expose asynchronous operations as asynchronous APIs (and synchronous operations as synchronous APIs).
Update: If you do want synchronous code to call asynchronous code, then you can use the Task.WaitAndUnwrapException extension method in my AsyncEx library. However, you still have the problems mentioned in Stephen Toub's post, namely these:
You can deadlock if your library doesn't use ConfigureAwait(false) everywhere it can.
You can also deadlock if you run into the maximum number of threads in the thread pool.
(2) is not that common anymore, but (1) is a real possibility. It's regularly brought up by people who are just testing out async so they mix it with synchronous code.

Creating an async method in .NET 4.0 that can be used with "await" in .NET 4.5

I have a .NET project that uses C# in .NET 4.0 and VS2010.
What I would like to do is add some async overloads to my library to make doing async programming easier for users in .NET 4.5 with the await keyword. Right now the methods that are being overloaded are non-asynchronous. Also I don't want to use any async methods myself, just create new ones and make them available.
Is creating async methods in .NET 4.0 and VS2010 possible and if so, what should the .NET 4.0 async method look like?
Because I'm using VS2010 I don't have access to the "async" keyword so what needs to happen to emulate that behavior in .NET 4.0? For example does it need to return any particular type, and does any code need to happen inside the method to make the currently non-asynchronous code it is calling happen asynchronously?
As others have stated, you start by having a method return Task or Task<TResult>. This is sufficient to await its result in .NET 4.5.
To have your method fit in as well as possible with future asynchronous code, follow the guidelines in the Task-based Asynchronous Pattern document (also available on MSDN). It provides naming conventions and parameter recommendations, e.g., for supporting cancellation.
For the implementation of your method, you have a few choices:
If you have existing IAsyncResult-based asynchronous methods, use Task.Factory.FromAsync.
If you have another asynchronous system, use TaskCompletionSource<TResult>.
The simplest way to do this is to return a Task or a Task<T>. That will be enough.
However this only makes sense if your method really executes asynchronously.
I also recommend that you follow the usual pattern of naming them like AbcAsync ("Async" suffix). Your callers will not notice any difference to an async method created with C# 5 (because there is none).
Tip: Just adding async to the method does nothing. Your method will execute sequentially and return a completed task. Making the method return a task must serve a certain purpose - usually this is done because the method inherently executes asynchronously (like a web-service call or file IO).
If your method only contains computation but no IO (or only blocking IO) it is usually better not to make it async because you gain nothing doing that. Async methods do not always execute on a separate thread. If that last sentence surprised you, you may want to dig a little into this topic.
As long as you return a Task that completes somehow (whether in a thread or asynchronously), you would support the async model..
Having a Task execute asynchronously is another story. If you had access to the async keyword and the API you could simply base your method on async calls to other, already supplied async methods. But in this case, you have to hand-craft your async Tasks.
There might be better ways to do it, but the most elegant way I can see (and have used) is to utilize System.Threading.Tasks.TaskCompletionSource to construct a task, use Begin/End model of asynchronous methods to execute whatever you need to execute. Then, when you have the result on hand, post it to the previously constructed Task instance using your completion source.
It will certainly be asynchronous, just not as fancy as the ones in upcoming release.
Disclaimer: I'm no way near an expert on this. Just made some experiments on.

Categories

Resources