在read()和pread()之间,哪种方式更有效?

时间:2013-12-13 07:11:25

标签: c linux performance

以下是readpread的声明:

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t pread(int fd, void *buf, size_t count, off_t offset); 

我们都知道它们具有几乎相同的功能,但哪一个更有效?

添加用例: 1.扫描一个大文件。 2.随机读一个大文件。

4 个答案:

答案 0 :(得分:8)

取决于您如何定义“高效”。如果你问的是性能差异是微观的。因此,请使用能够解决问题的方法。在许多情况下,当您处理从数据库中读取的线程时,pread是唯一的选择。在其他情况下,read是唯一明智的选择。问题有点不公平,因为pread的作用超过read。公平的比较是lseek + read,这肯定会慢于pread

让我们看一下在我可用的操作系统源中两者的实现差异。我从两个函数中删除了完全相同的代码以突出显示差异。代码要多得多。

这是pread的一部分:

vp = (struct vnode *)fp->f_data;
if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
        (vp->v_flag & VISTTY)) {
    return (ESPIPE);
}

offset = SCARG(uap, offset);
if (offset < 0 && vp->v_type != VCHR)
    return (EINVAL);

return (dofilereadv(p, fd, fp, &iov, 1, 0, &offset, retval));

这是read

的等效部分
return (dofilereadv(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval));

所以,pread会做一些额外的检查,以确保我们不会试图在管道,fifo,tty等上寻找它。它会检查我们是不是在读取字符的负偏移量设备。它也不会更新文件指针中的偏移量(代码中为fp)。

答案 1 :(得分:2)

这取决于您将使用read()pread()进行的操作

例如: 如果您正在阅读文件并且两次致电read()read()将自动推进指针。但是pread()保持相同的偏移量。

答案 2 :(得分:0)

这不是效率问题,而是功能问题。

如果我想从位置x及以后读取文件,我会使用lseek(如果需要),然后使用尽可能多的read

如果我想从文件中的随机位置读取并进行大量的来回跳转,那么我会使用pread代替lseek + read

有人会认为pread的效率略低于read,但效率略高于lseek + read。差异可能不会超过几个时钟周期。

答案 3 :(得分:0)

pread的主要优点是在多线程程序中,您不需要序列化I / O以防止另一个线程更改文件偏移量。

除此之外,差异最有可能发生在噪音中(但如果您真的感兴趣,请根据您的用例进行衡量!)。由于您的问题被标记为“linux”,因此IIRC在Linux内核中的低级I / O读取功能具有类似pread的界面。对于read()系统调用,它从文件表中查找偏移量,然后使用该偏移调用较低级别的读取函数,而pread()系统调用直接使用调用者提供的偏移量。所以我猜想pread()会比lseek()+ read()更有效率(一个系统调用不是主要优势),但在大多数情况下可能没什么值得担心的,因为系统调用在Linux上相对较快。