The whole SetSynchronizationContext is a red herring, it is just a sorting mechanism, work is still going on in the I / O thread pool.
What you are asking for is the queue method and the harvest. Asynchronous procedure calls for all your I / O operations from the main thread. Many higher-level structures wrap this functionality, the most famous of which is libevent .
There is a great description of the various options here: What is the difference between epoll, poll, threadpool? .
.NET already takes care of scaling for you by having a special “IO thread pool” that handles IO access when you call BeginXYZ methods. This I / O thread pool must have at least 1 thread per processor per box. see ThreadPool.SetMaxThreads .
If a single-threaded application is a critical requirement (for some crazy reason), you could, of course, combine all this using DllImport (see example here )
However, this would be a very difficult and risky task :
Why don't we support APC as a termination mechanism? APCs are really not a good general purpose completion mechanism for user code. The reinsertion control introduced by the BTR is virtually impossible; anytime when you lock a lock, for example, some arbitrary I / O termination may take your thread. He may try to acquire his own locks, which can lead to problems with ordering locks and, thus, to deadlock. Preventing this requires careful design and the ability to make sure that another user's code will never work during your expected wait, and vice versa. This greatly limits the usefulness of APC.
So, we repeat. If you need a controlled process with a single thread that does all its work using APC ports and termination, you will have to pass its code. Construction would be risky and difficult.
If you just need a high-performance network, you can continue to use BeginXYZ and the family, and be sure that it will work well, since it uses APC. You pay a negligible markup between threads and a specific .NET implementation.
From: http://msdn.microsoft.com/en-us/magazine/cc300760.aspx
The next step in server scaling is to use asynchronous I / O. Asynchronous I / O makes it easy to create and manage threads. This results in significantly simpler code, as well as a more efficient I / O model. Asynchronous I / O uses callbacks to process incoming data and connections, which means there are no lists to configure and scan, and there is no need to create new workflows to work with pending I / O.
An interesting side fact is that single threaded is not the fastest way to make asynchronous sockets on Windows using completion ports: http://doc.sch130.nsc.ru/www.sysinternals.com/ntw2k/info/comport. shtml
The goal of the server is to switch to the context as little as possible, as its threads avoid unnecessary blocking, while maximizing parallelism with multiple threads. The ideal thing is that there will be a thread actively serving the client request on each processor, and that these threads should not be blocked if there are additional requests waiting for the request to complete. However, for correct operation, there must be a way for the application to activate another thread when one processing of a client request is blocked during I / O (for example, when it reads from a file as part of processing).