Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5512123
  • 博文数量: 922
  • 博客积分: 19333
  • 博客等级: 上将
  • 技术积分: 11226
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-27 14:33
文章分类

全部博文(922)

文章存档

2023年(1)

2020年(2)

2019年(1)

2017年(1)

2016年(3)

2015年(10)

2014年(17)

2013年(49)

2012年(291)

2011年(266)

2010年(95)

2009年(54)

2008年(132)

分类: LINUX

2012-02-08 21:06:19

++++++APUE读书笔记-14高级输入输出-07readv和writev函数++++++

 

7、readv和writev函数
================================================
 readv和writev函数允许我们只通过一个函数调用,完成读取数据到不连续的缓存或者从不连续的缓存中向外写数据。这些操作被称作分散读和聚集写。
 #include
 ssize_t readv(int filedes, const struct iovec *iov , int iovcnt);
 ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);
 两个函数的会返回读取或者写入的字节数目,或者出错的时候返回错误。
 两个函数的第2个参数是一个指向iovec结构的数组的指针。
 struct iovec {
  void   *iov_base;   /* 缓存的起始地址 */
  size_t  iov_len;    /* 缓存的大小 */
 };
 iov数组的元素的数目通过参数iovcnt来指定。最多为IOV_MAX。参考资料中还用图示的方式表示了这个数组参数,这里不给出了,主要知道,数组的每个成员其实只是代表不同地址不同大小的缓存即可。
 writev函数依序从缓存iov[0],iov[1],...,iov[iovcnt]中收集输出数据,并返回输出数据的总字节大小,一般它就等于这些缓存的总长度。
 类似地,readv函数依序向每个数组元素填充数据,每次都填充完一个缓存元素之后再填充下一个元素,readv函数会返回被读取的总字节数。返回0代表没有数据,或者遇到了文件结束符号。
 这两个函数源于BSD4.2后来被添加到SVR4,它们被 Single UNIX Specification的XSI扩展包含。(尽管Single UNIX Specification将缓存地址iov_base设置为void*类型,但是还是有许多早期的实现使用char*类型)

 举例:
 在后面的章节中,我们的一个_db_writeidx函数需要连续地向一个文件写入缓存内容。第2个输出的缓存是一个调用者传入的参数,第一个缓存是我们自己创建的缓存,包含了第2个缓存的长度以及文件中其它信息的文件偏移量。有三种方式来实现这个:
 a)调用两次write函数,每次写一个buffer.
 b)分配一个我们自己的足够大的缓存,缓存包含了两个buffer,然后把两者拷贝到新的缓存中去。我们然后调用write一次写入这个新的缓存。
 c)调用writev来输出两个缓存。
 我们其实使用的writev来实现这个功能,但是比较其它两种方法,我们可以了解到更多的一些信息。

 图表中描述了三个方法的结果。
 我们的测试程序,输出一个100字节的头后面跟着200字节的数据。这个过程做1,048,576次,生成一个300兆的文件。测试程序分别对三种情况进行测试。我们使用times获取其写的前后的CPU时间,系统CPU时间,以及clock时间。所有三个时间用秒来描述。
 表格的具体内容,就不描述了,需要参见参考资料。实际我们将会看到,和调用write以及writev一次进行比较,系统cpu时间在我们两次调用write时候增加了。
 另外注意的就是(不要只局限于这里测试的两台机器),实际上,这里占用的总共CPU时间(用户和系统CPU时间之和),使用单次的write比writev要少(虽然少了,但是还是writev好,后面会说明原因)。因为单次write的时候,我们把用户级别的缓存拷贝到一个staging缓存中,然后当我们调用write的时候,内核将数据拷贝到它自己的内部缓存中。使用writev,我们拷贝的次数会减少了,因为内核只需要将数据直接拷贝到它的staging缓存中。对于writev函数的这一个调整带来的开销,在这里的少量数据中,虽然比实际的收益反而大了,但是随着数据量的增加,writev的性能将会越来越好,最终比write要好。
 总之,我们应该尝试使用所需最少数目的系统调用的方法来进行我们的工作。如果我们写入的数据量少,我们可以发现使用单一的write而不是使用writev会比较省。但是我们也可以发现,表现性能的好处,和实际管理我们buffer的代价之间需要做一个权衡。

参考:

 

 

阅读(853) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~