2013-12-13 64 views
5

readpreadの宣言は次のとおりです。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.Randomは1つの大きなファイルを読み込みます。

+0

pread protoの代わりに2回読み込まれているようです – ShinTakezou

+3

もう1つの関数は読み込み前に特定のオフセットにシークします。したがって、たとえば、 'lseek'に続いて' read'が 'pread'だけを使うより良いかどうかです。決定する1つの方法は、特定のユースケースに対して*ベンチマーク*することです。実際、私はそれを決める唯一の方法だと言っていますが、あなたのユースケースを知らないのでこの質問は答えられません。 –

+4

本当に心配していますか?違いがあれば、おそらく5-6クロックサイクルです。ディスクアクセスは25億〜30百万クロックサイクルです... – Damon

答えて

6

「効率的」をどのように定義するかによって異なります。あなたがパフォーマンスについて尋ねているならば、違いは微妙です。だからあなたのために問題を解決するものを使用してください。多くの場合、preadは、データベースなどから読み取ったスレッドを扱う場合の唯一のオプションです。他の場合にはreadが賢明なオプションです。そして、preadreadより多くなるので、質問はちょっと不公平です。公正な比較は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は、いくつかの余分なチェックが我々が求めてしようとしていないことを確認していpipe、fifo、ttyなどに置いて、文字デバイスから負のオフセットを読み取っていないことを確認します。また、ファイルポインタのオフセット(コード内のfp)も更新されません。

2

それはあなたがread()pread()例えば

でやろうとしている操作によって異なります。あなたは、ファイルを読んでいると、あなたが二回read()を呼び出す場合 、read()は自動的にポインタを進めます。しかし、pread()は同じオフセットにとどまります。

0

これは実際には効率の問題ではなく機能性の問題です。

xの位置以降のファイルを読みたい場合は、lseek(必要な場合)と、必要に応じて多くのreadを使用します。

ファイルのランダムな場所から読み込んで前後にジャンプする場合は、lseek + readの代わりにpreadを使用します。

preadは、readよりやや効率が低いと思われますが、lseek + readよりやや効率的です。この差は恐らく2クロックサイクルよりも大きくない。

+0

そして@jannebが他の答えで指摘したように、ファイルがスレッド間で共有されていて、読み込みがシリアル化されていない場合は、 'pread'を好むでしょう。 – rodrigo

0

preadの主な利点は、マルチスレッドプログラムでは、別のスレッドがファイルオフセットを変更しないようにI/Oをシリアル化する必要がないことです。

これ以外の違いは、ノイズの可能性が高いことです(ただし、本当に興味がある場合は、ユースケースを測定してください)。あなたの質問は、LinuxカーネルのIIRCの "linux"とタグ付けされているため、低レベルのI/O読み取り機能には先読みのようなインターフェースがあります。 read()システムコールでは、ファイルテーブルからのオフセットを検索し、そのオフセットを使って下位レベルの読み取り関数を呼び出します。一方、pread()システムコールは、呼び出し元から直接提供されたオフセットを使用します。だから私はpread()がlseek()+ read()よりも効率的になるだろうと考えているだろうが、syscallがLinux上で比較的高速であるため、ほとんどの場合心配する価値はないだろう。

関連する問題