Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

async/await for high performance server applications?

the new async/await keywords in C# 5 look very promising but I read an article about the performance impact on those applications since the compiler will generate a quite complex state machine for async methods.

Async-programming using these keywords is so much easier but is it as good as say SocketAsyncEventArgs for Sockets ?

Second question: Are asynchronous IO methods like Stream.WriteAsync really asynchronous (Completion Ports on .Net or epoll/poll on Mono) or are these methods cheap wrappers for pushing a write call to a threadpool ?

Third question: Beside the SynchronizationContext of an UI application, is there a way to implement some kind of sinlge-threaded context ? Something like an event loop so that finished tasks continues on the main thread ? I discovered the Nito.AsyncEx library, but I'm not quite sure whether or not this is what i need.

like image 816
Kr0e Avatar asked Feb 06 '13 21:02

Kr0e


People also ask

Does async await improve performance?

The main benefits of asynchronous programming using async / await include the following: Increase the performance and responsiveness of your application, particularly when you have long-running operations that do not require to block the execution.

When should you use async await?

Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.

What is the advantage of using async await?

A significant benefit of the async/await pattern in languages that support it is that asynchronous, non-blocking code can be written, with minimal overhead, and looking almost like traditional synchronous, blocking code.

Is async await faster than promises?

Yes, you read that right. The V8 team made improvements that make async/await functions run faster than traditional promises in the JavaScript engine.


2 Answers

async itself is quite performant. A ton of work went into this.

In general, on the server side you're concerned about async I/O. I'm going to ignore async CPU-bound methods because the async overhead will get lost in the noise anyway.

Asynchronous I/O will increase your memory usage per request, but it'll reduce your thread usage per request. So you end up winning (except borderline pathological corner cases). This is true for all asynchronous I/O, including async.

await was designed with a pattern - not just the Task type - so if you need to squeeze out as much performance as possible, you can.

I read an article about the performance impact on those applications since the compiler will generate a quite complex state machine for async methods.

The article you read by Stephen Toub is excellent. I also recommend the Zen of Async video (also by Stephen Toub).

Async-programming using these keywords is so much easier but is it as good as say SocketAsyncEventArgs for Sockets ?

First, understand that SocketAsyncEventArgs is more scalable because it reduces memory garbage. The simpler way to use async sockets will generate more memory garbage, but since await is pattern-based you can define your own async-compatible wrappers for the SocketAsyncEventArgs API (as seen on Stephen Toub's blog... I'm sensing a pattern here ;). This allows you to squeeze every ounce of performance out.

Though it's usually better in the long run to design a scale-out system rather than twisting the code to avoid a few memory allocations. IMHO.

Second question: Are asynchronous IO methods like Stream.WriteAsync really asynchronous (Completion Ports on .Net or epoll/poll on Mono) or are these methods cheap wrappers for pushing a write call to a threadpool ?

I don't know about Mono. On .NET, most asynchronous I/O methods are based on a completion port. The Stream class is a notable exception. The Stream base class will do a "cheap wrapper" by default, but allows derived classes to override this behavior. Streams that come from network communications always override this to provide truly asynchronous I/O. Streams that deal with files only override this if the stream was constructed explicitly for asynchronous I/O.

Third question: Beside the SynchronizationContext of an UI application, is there a way to implement some kind of single-threaded context ?

ASP.NET also has a SynchronizationContext, so if you're using ASP.NET you're already set.

If you are doing your own socket-based server (e.g., a Win32 service), then you could use the AsyncContext type in my AsyncEx library. But it doesn't sound like this is what you'd actually want. AsyncContext will create a single-threaded context on the current thread. But the true power of async for server applications comes from scaling requests instead of threads.

Consider how the ASP.NET SynchronizationContext works: as each request comes in, it grabs a thread pool thread and constructs a SynchronizationContext (for that request). When that request has asynchronous work to do, it registers with the SynchronizationContext and the thread running that request returns to the thread pool. Later, when the asynchronous work completes, it grabs a thread pool thread (any thread), installs the existing SynchronizationContext on it, and continues processing that request. When the request is finally completed, its SynchronizationContext is disposed.

The key in that process is that when the request is waiting (await) asynchronous operations, there are no threads dedicated to that request. Since a request is considerably lightweight compared to a thread, this enables the server to scale better.

If you gave each of your requests a single-threaded SynchronizationContext such as AsyncContext, this would bind a thread to each request even when it has nothing to do. That's hardly any better than a synchronous multithreaded server.

You may find my MSDN article on SynchronizationContext useful if you want to tackle inventing your own SynchronizationContext. I also cover in that article how asynchronous methods "register" and "install" the context; this is done mostly-automatically by async void and await so you won't have to do it explicitly.

like image 186
Stephen Cleary Avatar answered Sep 22 '22 20:09

Stephen Cleary


  1. If you're using it in the context of async IO it's a moot point. The time spent on your database operation, file/network IO, etc. will be milliseconds at best. The overhead of async will be microseconds at worst, if no nanoseconds. Where you need to be careful is when you have a lot of operations that you are awaiting (as in thousands, tens of thousands, or more) and those operations are very quick. When those async operations represent CPU bound work it's certainly possible for the overhead of using await to be at least noticeable. Note that the code generated for the state machine is somewhat complex, in terms of human understand-ability, but state machines in general tend to perform rather well as a whole.

  2. The methods are not just wrappers that block a thread pool thread, no. That would defeat the purpose of what await represents. Those methods don't block any thread and rely on OS hooks to complete the task.

  3. Sure, you can create your own SynchronizationContext instead of relying entirely on an existing one provided by your UI framework. Here is a great example. Just be careful when using something like this; it's a good tool for the right task, but can be abused to find a more creating way of blocking when you should just be doing everything asynchronously.

like image 20
Servy Avatar answered Sep 21 '22 20:09

Servy