Socket.ReceiveAsync可以去C10K吗?

Can Socket.ReceiveAsync head to C10K?

使用 Socket.ReceiveAsync or even Socket.SendAsync experience the C10K 的 TCP 套接字有问题吗?

我认为这与另一个问题完全不同,正如有人建议的那样: 这个问题更多的是对各种线程模型的讨论,这些模型并不总是适用于 Socket。****Async(它们都使用 SocketAsyncEventArgs)。

这个问题的答案在很大程度上取决于您的运行时间和 OS。我最近在为 Unity 开发解决方案时走上了这条路,所以即使问题有点老,我也会分享我所知道的。

让我们首先谈谈 Windows 和 MS .NET(从实现这些方法的 3.5 到现在的所有内容)。在此运行时和平台上组合这些套接字方法时,您绝对可以破坏 c10k。采用 SocketAsyncEventArgs 参数的 ****Async 方法直接在运行时进行本机调用,映射到 Windows 中的 IO 完成端口。这是一条通过运行时的特殊路径,它的作用不仅仅是防止分配 IAsyncResult 对象。我假设在 Linux 上使用 .NET Standard 也非常快,但我不能直接说。

接下来,让我们谈谈Linux上的Mono。具体来说,我目前正在建设: Mono C# 编译器版本 4.6.2.0 这也会破坏 c10k,但它的工作方式不同。据我所知,*****Async 方法在运行时采用与所有其他异步方法相同的路径,除了 ****Async 调用采用最短路径并避免 IAsyncResult 分配。运行时通过 IOSelector.Add 将您的请求作为 IOSelectorJob 提交。出于这个原因,****Async 方法的 none 在 Mono 中实际上会 return false,尽管我不会指望这种行为总是正确的。我假设在 Windows 上使用 Mono 同样快,但我不能这么说。

最后说一下Unity。我正在使用 2018.3.2f1,它具有 Mono 5.11.0 运行时,设置为 .NET 4.x 兼容。我不确定是否有可能在 Unity 中破坏 c10k。我不知道为什么,但我知道在 Mono 和 .NET 中轻松破坏 c10k 的相同实现甚至不会接近。我认为这是因为他们的线程池以某种方式设置不同......也许是为了适应他们的工作系统,但这只是一个暗中猜测。很奇怪的事情发生了,比如同步接受优于异步。永远不会得到回调的 AcceptAsync 请求,等等。

在 Unity 之外破解 c10k 的一些技巧: - 在你的 IO 完成回调中做尽可能少的事情。不要像 MSDN 示例那样在其中调用其他异步方法 - 如果您可以管理它,请不要因为您的设计而互相阻止对 SendAsync 和 ReceiveAsync 的调用。您不能使用相同的 arg 进行 2 次未完成的调用,但是您可以为 send/recv 同时拥有多个单独的 args(以及缓冲区)。但是请注意,排序可能会变得复杂,例如在同一个套接字上有多个未完成的 recvs 的情况下,并发队列从回调中调度 returned args - 如果你必须在线程之间共享资源,那么 System.Collections.Concurrent 是你的朋友。不要自己动手,因为这些容器不是您不打破 c10k 的原因,而且您将永远无法与这些婴儿所接受的测试量相提并论

祝你好运,玩得开心 :) 如果你发现了在 Unity 中取得成功的秘诀,请不要忘记告诉我。如果我这样做,我一定会更新这个。