views:

1317

answers:

4

Quick question here: is there any obvious benefit to use asynchronous communication with the NetworkStream class (generated by TcpClient), i.e. the BeginRead/BeginWrite methods rather than running a separate thread and using synchronous operations on that, i.e. Read/Write? My impression has been (it could easily be quite wrong) that the asynchronous operations are non-blocking and performed at OS-level (in the TCP stack perhaps?), with a thread pool item for the callback. I am thinking that it surely must be different from calling ThreadPool.QueueUserWorkItem on the synchronous method, or it there would be rather little point in providing it. Now, I'm fairly confident this is the sort of thing (OS-level calls) that happens for file I/O at least, but if someone could please clarify the matter regarding network (TCP) communication, it would be most helpful. Basically, I would like to know whether there's any specific benefit to either method (besides the obvious one of being able to use the BinaryReader/StreamReader classes with the synchronous calls).

A: 

As others have pointed out, the allocation of another thread to your process will impact you when you use the synchronous method as you increase the number of simultaneous connections.

However, if you know you will only ever have a small number of connections, I would say that it becomes a wash and you should choose the method that is most natural for your application.

In the case where the thread overhead is negligible, I would expect the two scenarios to play out like this.

Asynchronous:

  1. You make call to BeginRead / BeginWrite
  2. "The system" (framework / OS) is informed of what you want
  3. Read / Write completes
  4. "The system" tells a thread in the thread pool to call your callback
  5. You do whatever you need to do to complete the operation

Synchronous in another thread:

  1. You get a thread from the thread pool to handle the IO
  2. You make call to Read / Write
  3. "The system" (framework / OS) is informed of what you want
  4. Read / Write completes
  5. You do whatever you need to do to complete the operation

The only difference here is that step 4 from the Asynchronous call becomes step 1 in the synchronous in another thread case.

Jon Norton
Yeah, this was basically my other consideration. Hrmm, now I have the same two opposing views with which I started...
Noldorin
A thread, even if blocked, is a significant piece of resource (starting with its 1MB of stack space allocated from the process's VM space).
Richard
I'll buy that to an extent, but since we're talking about taking a thread from the pool here, I don't know that it matters much. My inclination would be to do whatever is most natural for the application unless I could prove I had a problem. Premature optimization and all...
Jon Norton
The difference is scalability. For one connection there isn't much difference, for 100 there is. When you're dealing with 10,000 connections then the synchronous method just doesn't work at all. And the OS has a lot of 'special magic' that means that the async version is VERY efficient.
Len Holgate
Which would be a provable problem. I think we all agree here :-)
Jon Norton
+7  A: 

There is a difference, if you use a Worker thread to call the synchronous version you will tie up one of the threads on a blocking call.

Whereas the Begin methods will not tie up a thread but will instead use a callback on an appropriate I/O signal, the call back will then run on a thread from the pool.

AnthonyWJones
Right, this is pretty much exactly what I suspected. So you would recommend using the Begin methods rather than the synchronous methods on a separate thread, where possible? It would seem more elegant, if not more efficient, to do it this way.
Noldorin
.NET framework implementation of low level (BeingXX/EndXX) pattern generally uses IO Completion ports. This is the most scalable IO approach available under Windows.
Richard
@Noldorin: Yes I would recommend using the Begin Methods primarily because the code is simpler that way, happily in this case the simpler approach is also more efficient.
AnthonyWJones
@Richard: Good to have some confirmation on that, cheers.@AnthonyWJones: Thanks very much, the answer is yours.
Noldorin
+1  A: 

I agree with AnthonyWJones, imagine your thread pool has 10 threads, but you have 100 passive enought clients. With async calls you can BeginRead for every one of them, and when data from some one is ready, it will be processed by one of the pool threads. But if you will try to use QueueUserWorkItem, you'll schedule data receiving from only 10 clients. And if they send nothing in 1 hour, other 90 clients will never get a chance to get data.

alex2k8
Indeed, I see that calling the Begin method clearly isn't equivalent to QueueUserItmem now... Still, the main point is how it compares to running a separate thread with synchronous operations.
Noldorin
There is no big difference if you explicitly use thread from a pool or create a number of threads yourself - any way you are limited in number of threads... With Async ops, the threads are used only to do the real job, and then released. With Sync ops the threads may be just blocked by idle wait.
alex2k8
Ok, that makes good sense now. Thanks for the explanations.
Noldorin
+1  A: 

I'm not really sure why NetworkStream even has a BeginRead/Write, since this basically violates the purpose of the NetworkStream in the first place. By using the Async methods, you gain faster response, greater scalability, and reduced resource consumption.

If you are only ever going to have one connection at a time, then it doesn't matter much if you use a thread pool thread or not, but if you accept many connections then you definitely want to use async.

Mystere Man
I see what you mean. These asynchronous methods would likely be better suited inside the TcpClient class. It seems like the consensus is leaning slightly towards using the async methods for better performance (if only marginally).
Noldorin