第十四章*高级I/O(七)--readv和writev函数
(2012-07-31 13:20)
原文地址:第十四章*高级I/O(七)--readv和writev函数 作者:yourtommy readv和write函数让我们在单个函数调用里从多个不连续的缓冲里读入或写出。这些操作被称为分散读(scatter read)和集合写(gather write)。
两个函数的第二个参数都是一个iovec结构体数组的指针: iov数组里的元素数量由iovcnt指定。它限制于IOV_MAX(第二章)。下图显示了这两个函数的参数和iovec结构体的关系: writev函数把缓冲的输出数据按顺序集合到一起:iov[0]、iov[1]、到iov[iovcnt-1];writev返回输出字节的总数量,它应该等于所有缓冲长度的和。 readv函数把数据按顺序分散到缓冲里,问题在处理下一个缓冲时填满第一个。readv返回被读的字节总数。如果没有更多数据和碰到文件末尾时返回0的计数。 这两个函数起源于4.2BSD,后来加入到SVR4。这两个函数被SUS的XSI扩展包含。 尽管SUS定义了缓冲地址为一个void *,然而许多未跟上标准的实现仍使用char *代替。 在20.8节里,函数_db_writeidx里,我们需要连续地写两个缓冲到一个文件。第二个要输出的缓冲是一个传给调用者的参数,而第一个缓冲是我们创建的,包含第二个缓冲的长度和文件里其它信息的一个文件偏移量。我们可以有三种方法做这个。 1、调用write两次,一个缓冲一次; 2、分配一个我们自己的缓冲,它足够大来包含两个缓冲,然后把两者拷贝到新缓冲。我们然后为这个新缓冲调用write一次。 3、调用writev来输出两个缓冲。 我们在20.8节使用的解决方案是使用writev,但是把它跟其它两种方案比较是有指导性的。 下表显示了提到的三种方法的结果。
我 们测量的测试程序输出一个100字节的头,接着一个200字节的数据。这被完成1048576次,产生一个300M的文件。测试程序有三个分离的条件-- 上表中每个测量的技术是一个。我们使用times(8.16节)来得到用户CUP时间,系统CPU系统和挂钟时间,在write前后。所有三个时间以秒显 示。 正如我们意料的,系统时间当我们调用两次write时增加,对比于一次的write或writev。这和3.9节的测量结果对应。 接 着,注意CPU时间的总和(用户加上系统),当我们执行缓冲拷贝接着单个write比单个writev调用要少。对于单个write,我们在用户层拷贝缓 冲到一个分段运输的缓冲,然后在我们调用write时内核会把数据拷贝到它内部的缓冲。对于writev,我们应该做更少的拷贝,因为内核只需要直接把数 据拷贝到它的分段运输缓冲里。然而,为如此少的数据使用writev的固定花费,比所得要大。当我们需要拷贝的数据量增加时,在我们程序里拷贝缓冲会便耗 时,而writev替代地将更具吸引力。 小必不要被上表中Linux相对于Mac的性能影响太多。这两个电脑非常不同:它们有不同的处理器架构、不同的RAM量、不同速度的磁盘。为了公平比较两个操作系统,我们需要使用相同的硬件。 总而言之,我们应该总是尝试使用所需的最少次数的系统调用来完成工作。如果我们写少量数据,那么我们将发现自己拷贝数据和使用单个write而不是使用writev会更不耗时。然而,我们可能发现,性能的好处比不上需要管理我们自己的分段运输缓冲的复杂性代价。 |
|
来自: android之情殇 > 《linux》