【问题标题】:libuv and uv_try_write: why multiple buffers?libuv 和 uv_try_write:为什么要使用多个缓冲区?
【发布时间】:2016-06-28 13:42:04
【问题描述】:

考虑uv_try_write 的文档(同样适用于uv_writeuv_write2)。
声明是:

int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs)

其中uv_buf_t 是一个至少具有以下字段的数据结构:

  • char* uv_buf_t.base
  • size_t uv_buf_t.len

我很确定我在这里遗漏了一些东西。

为什么应该提交多个uv_buf_t 结构而不是更大一个?
换句话说,如果我有 100 个 char 要写出来,为什么我要提交 10 个 uv_buf_t 包含每个 10 个 char 而不是一个 uv_buf_t 包含 100 个 char

现实世界的例子会很有帮助,在这个例子中这种选择是有意义的,因为我在阅读文档时无法弄清楚。

【问题讨论】:

  • 就我的理解而言,许多缓冲区意味着不同的“消息”,更大的缓冲区意味着更大的消息长度。
  • @LPs 无论如何,不​​同的消息是在不同的时间生成的,所以我可以在第一个可用时发送它,而没有实际理由等待下一个。我错了吗?
  • 例如,您可以考虑一个“服务”,它负责发送由不同任务/线程排队的消息。
  • @LPs 必须再次实施 Nagle 算法来决定何时交付所有内容的服务?否则,一旦唤醒,为什么不能多次调用uv_try_write?无论如何,我明白你的意思,不确定这是不是原因,但确实有道理。

标签: c libuv


【解决方案1】:

每当您执行格式化 I/O 时,您所做的只是连接一堆小字符串。

想想当你写类似的东西时,幕后发生了什么

fprintf(stdout, "Hello, %s!\n", getenv("USER"));

这可以实现(忽略getenv的多重评估)为:

struct iovec bufs[3] = {{"Hello, ", 7}, {getenv("USER"), strlen(getenv("USER"))}, {"!\n", 2}};
writev(STDOUT_FILENO, bufs, 3);

(在实践中,FILE 操作稍微复杂一些——也许没有必要如此——但大多数情况就是这么简单)。

允许直接指定多个缓冲区意味着您不必浪费处理时间(或源代码复杂性)在写入之前分配单个缓冲区来保存它们。


另外,您是否曾经在make -j 下运行编译器,导致其输出变得非常混乱?这通常是因为他们这样做 - 相反,他们发出几个单独的 writes 并且它们与来自并行进程的写入混合在一起,而不是在单个系统调用期间发出每一行。

【讨论】:

    【解决方案2】:

    大多数应用程序可能只使用一个,但由于 writev 是一个东西,我们也在 try 变体中公开它。想象一个应用程序充当代理,并获取多个数据包中的数据,然后需要中继这些数据包。一次检测属于同一数据包的所有缓冲区会将系统调用限制为 1,而不必为所有缓冲区分配空间,然后复制内容以调用 write

    您可以在此处阅读有关该方法的更多信息:https://en.wikipedia.org/wiki/Vectored_I/O

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-02
      • 1970-01-01
      相关资源
      最近更新 更多