0

使用Socket.ReceiveAsync甚至Socket.SendAsync的 TCP 套接字会遇到C10K问题吗?

4

1 回答 1

1

我认为这根本不是另一个问题的重复,正如建议的那样: Async-Await vs ThreadPool vs MultiThreading on High-Performance Sockets (C10k Solutions?) 这个问题更多的是对各种线程模型的讨论,其中并不总是适用于 Socket.****Async(全部使用 SocketAsyncEventArgs)。

这个问题的答案在很大程度上取决于您的运行时和您的操作系统。我最近在为 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 提交。由于这个原因,在 Mono 中,似乎没有一个 ****Async 方法实际上会返回 false,尽管我不会指望这种行为总是正确的。我假设在 Windows 上使用 Mono 也同样快,但我不能说。

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

在 Unity 之外打破 c10k 的一些技巧: - 在 IO 完成回调中尽可能少地执行。不要像 MSDN 示例那样在其中调用其他 Async 方法 - 如果您可以管理它,请不要因为您的设计而对 SendAsync 和 ReceiveAsync 的调用相互阻塞。您不能有 2 个具有相同 arg 的未完成调用,但您可以同时拥有多个和单独的 args(因此缓冲区)用于发送/接收。但是请注意,排序可能会变得复杂,例如,在同一个套接字上有多个未完成的接收,以及并发队列从回调中分派返回的参数的情况下 - 如果您必须在线程之间共享资源,那么 System.Collections.Concurrent是你的朋友。不要自己动手,因为这些容器不是你不破坏 c10k 的原因,

祝你好运,玩得开心 :) 如果你在 Unity 中找到成功的秘诀,别忘了告诉我。如果我这样做,我肯定会更新这个。

于 2019-01-28T03:39:38.410 回答