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).
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:
- You make call to BeginRead / BeginWrite
- "The system" (framework / OS) is informed of what you want
- Read / Write completes
- "The system" tells a thread in the thread pool to call your callback
- You do whatever you need to do to complete the operation
Synchronous in another thread:
- You get a thread from the thread pool to handle the IO
- You make call to Read / Write
- "The system" (framework / OS) is informed of what you want
- Read / Write completes
- 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.
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.
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.
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.