【问题标题】:C# Socket: is multiple sending less efficient than a single send?C# Socket:多次发送比一次发送效率低吗?
【发布时间】:2021-12-06 07:06:29
【问题描述】:

我正在编写一个服务于数千个连接的高吞吐量服务器。假设我有 400 个字节要通过套接字发送。假设我有两种方式:

  1. 调用 Socket.Send() 40 次,每次发送 10 个字节。
  2. 调用 Socket.Send() 一次,发送 400 个字节。

这两种方式在速度、CPU 负载等方面有很大的不同吗?

【问题讨论】:

  • 你可以测量它,但它不应该有所作为。 Send 本质上是“将这些字节放入缓冲区”,何时将缓冲区中的字节发送到网络上的决定不受此控制。
  • 调用任何你不必调用的函数都是低效的
  • @user253751 在技术上是正确的,但在许多情况下(当然不是所有情况)差异并不重要;与往常一样,正如 Damien 指出的那样:如果它可能很重要,那么你需要衡量它

标签: c# sockets


【解决方案1】:

如果Socket.NoDelay 保留在false,那么它几乎不会产生任何影响——大多数时候,你只是在本地缓冲——尽管P/Invoke 开销比绝对必要的要多一些(由于通过套接字层进行了大量调用)。请注意,Socket.NoDelay 通常应在您关心的任何地方设置为 true。

如果Socket.NoDelay 是true,那么如果一切正常,那么您可能通过使用 40 个 10 字节的发送来引入额外的数据包分段,这将使用 400 字节的一次发送时应避免。然而,在许多情况下,操作系统/硬件堆栈中的各种抽象和层意味着很多 10 字节块可能最终会共享数据包。不过,在最佳情况下,这仍然比 1 多得多。

还请注意,这始终是一种权衡:数据包碎片会降低整体吞吐量,但如果其他 390 个字节将占用可测量(但可能很少)的构建时间。

在大多数情况下:这不太可能成为瓶颈。如果您可以避免数据包碎片化而不会导致延迟,那可能是可取的。如果是我,我可能会更关心有效的缓冲区管理,以最大限度地提高可伸缩性,同时避免由于 GC 导致的暂停;新的“管道”IO API 之类的工具可以真正帮助解决这个问题,并且 Kestrel 可用于托管基于“管道”的 TCP 服务器,其代码比您编写时使用的代码更少您自己的套接字侦听器 - 然后它会为您处理所有缓冲区管理。

【讨论】:

  • 感谢您的专家建议 - 对我帮助很大。
猜你喜欢
  • 1970-01-01
  • 2016-11-12
  • 1970-01-01
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
  • 2018-07-14
相关资源
最近更新 更多