views:

1101

answers:

5

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?

+4  A: 

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.

casperOne
Doesn't it end up firing off a thread to actually do the asynchronous work though? Doesn't the creation/destruction of threads from that create more overhead than a threadpool?
ryeguy
A: 

I prefer thread pool as it helps me manage the number of the thread that I constrain at system level.

You need clarify what you mean by efficiency:

  1. Less memory
  2. speed
  3. Response time/throughput

you need to make a decision using

  1. Average number of users using the program
  2. hardware

Iron out the fundamental requirements first before leaping into design choices.

The key words of his question were "scalable multi-user". Threadpool doesn't scale because there's only a limited number of threads available from the Threadpool.
Mystere Man
+1  A: 

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.

Mystere Man
+1  A: 

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.

Nick Gunn
+1  A: 

Regarding your edit, begin/end calls generally will not spawn a thread. That is pretty much the reason they exist. They allow you to start an operation that is expected to run asynchronously, in the most efficient manner available. For sockets, why should it spawn a thread? The OS will notify you when something happens on a socket, so there's no need for a thread to hang around listening as well.

jalf