libuv 和 uv_try_write:为什么有多个缓冲区?
libuv and uv_try_write: why multiple buffers?
考虑 uv_try_write
的文档(同样适用于 uv_write
和 uv_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 char
的 10 uv_buf_t
而不是包含 100 char
的 uv_buf_t
?
在真实世界示例中这样的选择是有意义的,因为我在阅读文档时无法理解它。
大多数应用程序可能只使用一个,但由于 writev
是我们在 try 变体中公开它的东西。想象一个应用程序充当代理,并在多个数据包中获取数据,然后需要中继这些数据。一次检测属于同一个数据包的所有缓冲区将系统调用限制为 1,而不必为所有缓冲区分配 space,然后复制内容只是为了调用 write
.
您可以在此处阅读有关此方法的更多信息:https://en.wikipedia.org/wiki/Vectored_I/O
每当您执行格式化 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
下的编译器导致其输出变得非常混乱?这通常是因为它们 而不是 这样做 - 相反它们发出几个单独的 write
s 并且它们与并行进程的写入混合在一起,而不是在单个过程中发出每一行系统调用。
考虑 uv_try_write
的文档(同样适用于 uv_write
和 uv_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 char
的 10 uv_buf_t
而不是包含 100 char
的 uv_buf_t
?
在真实世界示例中这样的选择是有意义的,因为我在阅读文档时无法理解它。
大多数应用程序可能只使用一个,但由于 writev
是我们在 try 变体中公开它的东西。想象一个应用程序充当代理,并在多个数据包中获取数据,然后需要中继这些数据。一次检测属于同一个数据包的所有缓冲区将系统调用限制为 1,而不必为所有缓冲区分配 space,然后复制内容只是为了调用 write
.
您可以在此处阅读有关此方法的更多信息:https://en.wikipedia.org/wiki/Vectored_I/O
每当您执行格式化 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
下的编译器导致其输出变得非常混乱?这通常是因为它们 而不是 这样做 - 相反它们发出几个单独的 write
s 并且它们与并行进程的写入混合在一起,而不是在单个过程中发出每一行系统调用。