Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# begin*() method vs threadpool for a server

For making a scalable multiuser server in C#, which of these two types of servers are more efficient? You can see an example of the async server using the begin* methods (like beginaccept, beginsend) here, and the threadpool implementation here.

I know what a threadpool is and how it works so I pretty much understand how that implementation works. What about the async server though? Does that spawn a thread for each and every send, receive, and connection event? How efficient is that vs a threadpool?

By efficiency I just mean a general balance of speed and memory use.

edit:

It has been suggested to me to use the begin() methods, but don't these create overhead when they spawn a new thread to take care of the send, receive, or connect event? Or do they end up using some kind of internal threadpool? If not, is there a way to make it so it does use a threadpool or should I just roll my own async socket server?

like image 884
ryeguy Avatar asked Feb 19 '09 19:02

ryeguy


3 Answers

The TcpServer implementation is going to be better, as it's going to take advantage of I/O completion ports to perform the asynchronous work, while the threadpool implementation is generally going to have to burn a thread to wait on the connections that are being accepted.

Generally speaking, use the async methods on things like files, databases, sockets (things that have an underlying unmanaged implementation to them) as they will utilize I/O completion ports for their work, which is generally more efficient than moving the code to the thread pool. However, it is going to add complexity to your code, so that is something you have to account for.

like image 56
casperOne Avatar answered Oct 26 '22 22:10

casperOne


If by scalable, you mean really large numbers of connections, you should also consider a number of other aspects beyond use of the thread-pool.

1) If you are using .NET3.5, consider SocketAsyncEventArgs rather than the BeginXXX/EndXXX. The approach is described in MSDN Magazine. These allow for more efficient dispatch and processing of the underlying async i/o.

2) Consider your memory usage very carefully. Byte[] buffers allocated for asynchronous i/o are pinned, forcing the GC to work around them during the compaction phase which in turn may result in fragmentation and OutOfMemoryExceptions under load. Also, you have consider the lower-level native issues of async i/o such as available memory in the non-paged pool.

Some of the available techniques are using a single shared zero-byte buffer for all pending receives, and using pooled buffers (from memory that does not compacted - either LOH or native heap) for I/O that will actually transfer data.

like image 41
Nick Gunn Avatar answered Oct 27 '22 00:10

Nick Gunn


A better approach may be to use Jeffery Richter's AsyncEnumerator. It's part of the Wintellect PowerThreading Library. You can watch a video presentation of how it works over at Channel 9.

I'm using it in two projects, and the great thing about it is that it allows you to share the limited resources of the threadpool across many requests, so it doesn't tie up threads for each request. You get the best of both worlds.

like image 45
Erik Funkenbusch Avatar answered Oct 27 '22 00:10

Erik Funkenbusch