ReceiveAsync与BeginReceive的性能

hai*_*yyu 7 c# sockets performance asynchronous tcp

我正在编写客户端应用程序,我想知道是否应该使用Socket类的ReceiveAsync或BeginReceive方法.到目前为止,我一直在使用后者,但是,我发现它似乎对CPU有很大的压力.这是我的接收循环基本上看起来像:

private void socket_ReceiveCallback(IAsyncResult result_)
{
    // does nothing else at the moment
    socket.EndReceive(result_);
    byte[] buffer = (byte[])result_.AsyncState;

    // receive new packet
    byte[] newBuffer = new byte[1024];
    socket.BeginReceive(newBuffer, 0, newBuffer.Length, SocketFlags.None, 
                        socket_ReceiveFallback, newBuffer);
}
Run Code Online (Sandbox Code Playgroud)

现在我一直想知道我在这里做错了什么,因为其他通信应用程序根本不会给CPU带来压力.而且我想知道我是否会更好地使用SocketAsyncEventArgs和ReceiveAsync.

所以这是我的问题:

为什么我的循环如此强调CPU?我应该使用SocketAsyncEventArgs和ReceiveAsync而不是BeginReceive吗?

Fre*_*red 8

BeginReceiveEndReceive是在 C# 5 中引入现代asyncawait关键字之前使用的旧遗留异步模式的残余。

因此,您应该更喜欢使用ReceiveAsyncoverBeginReceiveEndReceive进行异步编程。

对于真正的高性能场景,您应该使用SocketAsyncEventArgs. 这是为高性能而设计的,由Kestrel Web 服务器使用。

来自SocketAsyncEventArgs 文档的备注部分

SocketAsyncEventArgs 类是 System.Net.Sockets.Socket 类的一组增强功能的一部分,这些增强功能提供了可供专门的高性能套接字应用程序使用的替代异步模式。该类专为需要高性能的网络服务器应用程序而设计。应用程序可以专门或仅在目标热点区域(例如,当接收大量数据时)使用增强型异步模式。

这些增强功能的主要特点是避免在大容量异步套接字 I/O 期间重复分配和同步对象。当前由 System.Net.Sockets.Socket 类实现的 Begin/End 设计模式要求为每个异步套接字操作分配一个 System.IAsyncResult 对象。

在新的 System.Net.Sockets.Socket 类增强功能中,异步套接字操作由应用程序分配和维护的可重用 SocketAsyncEventArgs 对象来描述。高性能套接字应用程序最了解必须维持的重叠套接字操作的数量。应用程序可以创建所需数量的 SocketAsyncEventArgs 对象。例如,如果服务器应用程序需要始终有 15 个未完成的套接字接受操作来支持传入客户端连接速率,则它可以为此目的分配 15 个可重用的 SocketAsyncEventArgs 对象。


usr*_*usr 6

我一直在localhost环回连接上对同步和异步套接字进行基准测试.我的结果是异步版本慢了大约30%.考虑到异步IO现在风靡一时,这对我来说是令人惊讶的.我用了多少线程并不重要.我可以使用128个线程,但同步IO更快.

我相信,原因是异步IO需要更多的分配和更多的内核模式转换.

因此,如果您不期望数百个同时连接,则可以切换到同步IO.