Socket有这些new async methods since .NET 3.5用于SocketAsyncEventArgs(例如Socket.SendAsync()),它们使用IO完成端口并避免需要继续分配。
我们使用一个简单的界面创建了一个名为 UdpStream 的类 - 只需 StartSend 和已完成事件。它分配两个SocketAsyncEventArgs,一个用于发送,一个用于接收。 StartSend只是使用SendAsync调度消息,并且每秒调用大约10次。我们在接收SocketAsyncEventArgs上使用Completed事件,并在处理完每个事件后,我们所有的ReceiveAsync都会形成一个接收循环。同样,我们每秒大约收到10次。
我们的系统需要支持 500 这些 UdpStream 对象。换句话说,我们的服务器将与500个不同的IP端点同时通信。
我在MSDN SocketAsyncEventArgs示例中注意到它们分配了N x SocketAsyncEventArgs,一个用于您希望一次处理的每个未完成的接收操作。我不清楚这与我们的场景究竟有什么关系 - 在我看来,也许我们没有得到SocketAsyncEventArgs的好处,因为我们只是为每个端点分配一个。如果我们最终获得500个SocketAsyncEventArgs,我认为我们将无法获益。也许我们仍然可以从IO完成端口获得一些好处?
此设计是否正确使用SocketAsyncEventArgs 缩放到500?
对于我们使用单个“UdpStream”的情况,有 使用SocketAsyncEventArgs与使用旧的Begin / End API相比有什么好处?
答案 0 :(得分:10)
在我看来,也许我们没有得到SocketAsyncEventArgs的好处,因为我们只是为每个端点分配一个。如果我们最终获得500个SocketAsyncEventArgs,我认为我们将无法获益。
仍然有很大的好处。
如果您使用APM模式(开始/结束方法),则每个BeginSend
和每个BeginReceive
都会分配一个IAsyncResult实例。这意味着有一个完整的类/对象分配大约每秒发生10,000次(500 * 10 [发送] + 500 * 10 [接收])。这会给系统带来巨大的额外开销,因为它会增加很多GC压力。
切换到针对高性能网络应用程序的新建议方法,您需要为每个方法调用预分配SocketAsyncEventArgs
实例(500)和重用它们,从而消除创建的GC压力在这些行动中。
答案 1 :(得分:6)
自从.NET 3.5与SocketAsyncEventArgs(例如Socket.SendAsync())一起使用时,Socket有了这些新的异步方法,因此它们使用IO完成端口并避免需要继续分配,从而有利于它。
Begin / End方法也使用IO完成端口。
imho你应该坚持你所知道的,因为你会让产品更快地运行起来。但我也会创建一个严格的IO处理类来处理传输。如果传输性能被证明是瓶颈,则可以更轻松地切换到新模型。对于我们使用单个“UdpStream”的情况,使用SocketAsyncEventArgs与使用较旧的Begin / End API相比有什么好处?