Pitfalls of wrapping callback async methods with Task async methods? - c#

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.

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.

how extensively should the async/await pattern be used?

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.

create asynchronous and synchronous methods for a repository

I have a repository with a method Insert that returns an int (the methods and types are not relevant here). I am thinking to create synchronous and asynchronous insert methods for this repository. For the asynchronous method is it a good practice to enclose the synchronous Insert method in a task to avoid the code duplication?
No, this is not a good practice, as detailed by Microsoft's Stephen Toub here:
https://blogs.msdn.microsoft.com/pfxteam/2012/03/24/should-i-expose-asynchronous-wrappers-for-synchronous-methods/
... and by Stephen Cleary here:
http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html
Long story short, if all your method does is wrap a synchronous call in Task.Run, that's trivial and I'm sure the caller is perfectly capable of doing it themselves. There is no need to increase the surface area of your API unless you have a naturally asynchronous operation (or unless you know that in the future you'll be able to provide one, and therefore want the consumers to target the XxxAsync method from day one).
As a bonus, here's a real life example of async wrapper methods being removed from a popular library:
JSON.NET used to provide SerializeAsync and DeserializeAsync methods which were just wrappers around their synchronous counterparts using Task.Factory.StartNew. Those were eventually obsoleted as they don't add value to the API and were deemed a potential scalability issue. The full discussion which led to this change can be found here:
https://github.com/JamesNK/Newtonsoft.Json/issues/66

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.

what is the main difference between .net Async and google go light weight thread

When calling runtime.GOMAXPROCS(1) in go the runtime will only use one thread for all your goroutines. When doing io your goroutines will yield and let the other goroutines run on the same thread.
This seem very similar to me to how the .net Async CTP feature is doing cooperative concurrency if you are not using background thread.
My question is which advantage or drawback could you think of one methode over the other.
Making value judgements is always a tricky thing so I'll highlight 3 differences. You decide whether they fall into the "pro" or "con" bucket.
While both Go and async allow you to write async code in a straightforward way, in .NET you have to be aware which part of your code is async and which one isn't (i.e. you have to explicitly use async/await keywords). In Go you don't need to know that - the runtime makes it "just work", there is no special syntax to mark async code.
Go design doesn't require any special code in standard library. .NET required adding new code to the standard library for every async operation, essentially doubling API surface for those cases e.g. there's new async http download API and the old, non-async http download API has to remain for backwards compatibility.
Go design and implementation is orders of magnitude simpler. A small piece of runtime code (scheduler) takes care of suspending goroutines that block on system calls and yielding to sleeping goroutines. There is no need for any special async support in standard library.
.NET implementation first required adding the aforementioned new APIs. Furthermore .NET implementation is based on compiler rewriting code with async/await into an equivalent state machines. It's very clever but also rather complicated. The practical result was that the first async CTP had known bugs while Go's implementation was working pretty much from the beginning.
Ultimately, it doesn't really matter. async/await is the best way to write async code in .NET. Goroutines are the best way to get that in Go. Both are great, especially compared to alternatives in most other languages.

Categories

Resources