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.
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 usingawait
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.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.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.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 ignoreasync
CPU-bound methods because theasync
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 theTask
type - so if you need to squeeze out as much performance as possible, you can.The article you read by Stephen Toub is excellent. I also recommend the Zen of Async video (also by Stephen Toub).
First, understand that
SocketAsyncEventArgs
is more scalable because it reduces memory garbage. The simpler way to useasync
sockets will generate more memory garbage, but sinceawait
is pattern-based you can define your ownasync
-compatible wrappers for theSocketAsyncEventArgs
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.
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. TheStream
base class will do a "cheap wrapper" by default, but allows derived classes to override this behavior.Stream
s that come from network communications always override this to provide truly asynchronous I/O.Stream
s that deal with files only override this if the stream was constructed explicitly for asynchronous I/O.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 ofasync
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 aSynchronizationContext
(for that request). When that request has asynchronous work to do, it registers with theSynchronizationContext
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 existingSynchronizationContext
on it, and continues processing that request. When the request is finally completed, itsSynchronizationContext
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 asAsyncContext
, 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 ownSynchronizationContext
. I also cover in that article how asynchronous methods "register" and "install" the context; this is done mostly-automatically byasync void
andawait
so you won't have to do it explicitly.