Socket有这些new async methods since .NET 3.5用于SocketAsyncEventArgs(例如Socket.SendAsync()),有利于他们使用IO完成端口并避免需要继续分配 .
我们用一个简单的接口创建了一个名为 UdpStream 的类 - 只需要StartSend和一个Completed事件 . 它分配两个SocketAsyncEventArgs,一个用于发送,一个用于接收 . StartSend只是使用SendAsync调度消息,并且每秒调用大约10次 . 我们在接收SocketAsyncEventArgs上使用Completed事件,并在处理完每个事件后,我们所有的ReceiveAsync都会形成一个接收循环 . 同样,我们每秒大约收到10次 .
我们的系统需要支持最多 500 的这些UdpStream对象 . 换句话说,我们的服务器将与500个不同的IP endpoints 同时通信 .
我注意到在MSDN SocketAsyncEventArgs示例中他们分配了N x SocketAsyncEventArgs,一个用于您希望一次处理的每个未完成的接收操作 . 我不清楚这与我们的场景究竟有什么关系 - 在我看来,也许我们没有得到SocketAsyncEventArgs的好处,因为我们只是为每个 endpoints 分配一个 . 如果我们最终获得500个SocketAsyncEventArgs,我认为我们将无法获益 . 也许我们仍然可以从IO完成端口获得一些好处?
-
Does this design make correct use of SocketAsyncEventArgs when scaling to 500?
-
For the case where we have a single "UdpStream" in use, is there any benefit to using SocketAsyncEventArgs vs using the older Begin/End API?
2 回答
仍然有很大的好处 .
如果使用APM模式(开始/结束方法),则每个
BeginSend
和每个BeginReceive
分配一个IAsyncResult实例 . 这意味着's a full class/object allocation occurring roughly 10,000 times per second (50010 [send] + 50010 [receive]). This puts a huge amount of extra overhead in the system since it'将增加很多GC压力 .切换到高性能网络应用程序的新建议方法,您需要预先分配
SocketAsyncEventArgs
实例(500)并在每次方法调用时重复使用它们,从而消除在这些操作期间创建的GC压力 .Begin / End方法也使用IO完成端口 .
imho你应该坚持你所知道的,因为你会让产品更快地运行起来 . 但我也会创建一个严格的IO处理类来处理传输 . 如果传输性能被证明是瓶颈,则可以更轻松地切换到新模型 .