Write a well designed asynchronous / non-asynchronous API

I ran into the problem of developing methods that perform network I / O (for a reusable library). I read this question

C # 5 await / async in API design

as well as others closer to my problem.

So the question is, do I want to provide the async and non-async method , how should I design them?

For example, to open a non-asynchronous version of a method, I need to do something like

public void DoSomething() { DoSomethingAsync(CancellationToken.None).Wait(); } 

and I feel that this is not a great design. I would like to offer (for example) a proposal on how to define private methods that can be wrapped in public methods to provide both versions.

+44
design c # asynchronous
Feb 14 '13 at 8:17
source share
2 answers

If you want the most convenient option, use only the async API, which is implemented without any blocking calls or using streaming thread streams.

If you really want to have both async and synchronous APIs, you will run into a maintainability problem. You really need to implement it twice: once async and once synchronously. Both of these methods will look almost identical, so the initial implementation will be simple, but you will get two separate almost identical methods, so maintenance will be problematic.

In particular, there is no simple and easy way to just make async or a synchronous wrapper. Stephen Tub has the best information on the topic:

(short answer to both “no” questions)

+46
Feb 14 '13 at 13:54
source share

I agree with Marx and Stephen (Cleary).

(BTW, I started writing this as a comment on Stephen, but it turned out to be too long, let me know whether it is normal to write it as an answer or not, and feel free to take a bit from and add it to Stephen's answer, in the spirit of “providing the best answer” )

It really "depends": as Mark said, it is important to know how DoSomethingAsync is asynchronous. We all agree that it makes no sense to use the "sync" method to call the "async" and "wait" methods: this can be done in the user code. The only advantage of using a separate method is to have an actual performance gain, to have an implementation that is different under the hood and adapted to a synchronous scenario. This is especially true if the async method creates a thread (or receives it from a threadpool): you get something that uses two “control flows” underneath, while a “promising” one with its synchronous look should execute in the caller’s contexts. It may even have concurrency problems, depending on the implementation.

Also in other cases, such as the intense I / O that the OP mentions, it might be worth having two different implementations. Most operating systems (of course, Windows) have different I / O mechanisms adapted to two scenarios: for example, performing async and I / O operations have great advantages over OS-level mechanisms such as I / O completion ports, which add a bit of overhead expenses (not significant, but not zero) in the core (in the end, they should do accounting, shipping, etc.) and a more direct implementation for synchronous operations. The complexity of the code also varies greatly, especially in those functions where several operations are performed / coordinated.

What would I do:

  • have some examples / tests for typical use and scenarios
  • see which version of the API is used, where and measure. Also measure the performance difference between the pure sync and sync options. (not for the whole API, but for a few typical cases).
  • Based on the measurement, decide if the extra cost is worth it.

This is mainly because the two goals somehow contrast with each other. If you need supported code, the obvious choice is synchronization from the point of view of async / wait (or vice versa) (or, even better, provide only an asynchronous option and allow the user to "wait"); if you need performance, you must implement two functions in different ways, use different basic mechanisms (from the framework or from the OS). I think this should not change in terms of unit testing, how you actually implement your API.

+2
Feb 21 '13 at
source share



All Articles