以下是read
和pread
的声明:
#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.随机读一个大文件。
答案 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上相对较快。