Performance of ReceiveAsync vs. BeginReceive
BeginReceive
and EndReceive
are remnants of the old legacy asynchronous pattern that were used before the introduction of the modern async
and await
keywords in C# 5.
So you should prefer to use ReceiveAsync
over BeginReceive
and EndReceive
for asynchronous programming.
For really high performance scenarios you should use SocketAsyncEventArgs
. This was designed for high performance and is used by the Kestrel web server.
From the remarks section for the SocketAsyncEventArgs documentation
The SocketAsyncEventArgs class is part of a set of enhancements to the System.Net.Sockets.Socket class that provide an alternative asynchronous pattern that can be used by specialized high-performance socket applications. This class was specifically designed for network server applications that require high performance. An application can use the enhanced asynchronous pattern exclusively or only in targeted hot areas (for example, when receiving large amounts of data).
The main feature of these enhancements is the avoidance of the repeated allocation and synchronization of objects during high-volume asynchronous socket I/O. The Begin/End design pattern currently implemented by the System.Net.Sockets.Socket class requires a System.IAsyncResult object be allocated for each asynchronous socket operation.
In the new System.Net.Sockets.Socket class enhancements, asynchronous socket operations are described by reusable SocketAsyncEventArgs objects allocated and maintained by the application. High-performance socket applications know best the amount of overlapped socket operations that must be sustained. The application can create as many of the SocketAsyncEventArgs objects that it needs. For example, if a server application needs to have 15 socket accept operations outstanding at all times to support incoming client connection rates, it can allocate 15 reusable SocketAsyncEventArgs objects for that purpose.
I have been benchmarking synchronous vs. asynchronous socket on on a localhost loopback connection. My results were that the asynchronous version was about 30% slower. That was surprising to me considering that async IO is all the rage now. It didn't matter how many threads I used. I could use 128 threads and still synchronous IO was faster.
The reason for that is, I believe, that async IO requires more allocations and more kernel mode transitions.
So you could just switch to synchronous IO, if you don't expect hundreds of simultaneous connections.