【发布时间】:2012-05-18 05:02:16
【问题描述】:
在 scatter 和 gather(即readv 和 writev)中,Linux 读取多个缓冲区并从多个缓冲区写入。
如果说,我有一个包含 3 个缓冲区的向量,我可以使用 readv,或者我可以使用单个缓冲区,它具有 3 个缓冲区的组合大小并执行 fread。
因此,我很困惑:对于哪些情况应该使用分散/聚集,什么时候应该使用单个大缓冲区?
【问题讨论】:
在 scatter 和 gather(即readv 和 writev)中,Linux 读取多个缓冲区并从多个缓冲区写入。
如果说,我有一个包含 3 个缓冲区的向量,我可以使用 readv,或者我可以使用单个缓冲区,它具有 3 个缓冲区的组合大小并执行 fread。
因此,我很困惑:对于哪些情况应该使用分散/聚集,什么时候应该使用单个大缓冲区?
【问题讨论】:
readv、writev提供的主要便利是:
writev,则向量中的所有元素都将写入一个连续的操作中,其他进程完成的写入不会发生在它们之间。例如比如说,您的数据是自然分段的,并且来自不同的来源:
struct foo *my_foo;
struct bar *my_bar;
struct baz *my_baz;
my_foo = get_my_foo();
my_bar = get_my_bar();
my_baz = get_my_baz();
现在,所有三个“缓冲区”都不是一个大的连续块。但是无论出于何种原因,您都希望将它们连续写入文件(例如,它们是文件格式的文件头中的字段)。
如果您使用write,您必须在以下选项中进行选择:
memcpy(开销)将它们复制到一个内存块中,然后调用write。然后写入将是原子的。write 进行三个单独的调用(开销)。此外,来自其他进程的 write 调用可以散布在这些写入之间(不是原子的)。如果你改用writev,一切都很好:
memcpy 可以从三个系统调用中创建一个缓冲区。所以你会做这样的事情:
struct iovec iov[3];
iov[0].iov_base = my_foo;
iov[0].iov_len = sizeof (struct foo);
iov[1].iov_base = my_bar;
iov[1].iov_len = sizeof (struct bar);
iov[2].iov_base = my_baz;
iov[2].iov_len = sizeof (struct baz);
bytes_written = writev (fd, iov, 3);
来源:
【讨论】:
Linux System Programming 书中,他们说readv or writev can experience any of the errors of the read() and write() system calls, and will, upon receiving such errors, set the same errno codes. 那么readv 会返回EINTR 吗?或者在 readv 的原子读取之间发生的信号会发生什么?它会被忽略还是排队。
readv() 或writev() 期间到达,这些系统调用(取决于SA_RESTART)将返回比请求更少的字节。