read
なぜより遅いのですかgetc
?
たとえば、次のようになります。
for (;;) {
chr++;
amr=read(file1, &wc1, 1);
amr2=read(file2, &wc2, 1);
if (wc1 == wc2) {
if (wc1 == '\n')
line++;
if (amr == 0) {
if (eflg)
return (1);
return (0);
}
continue;
}
それより遅い:
for (;;) {
chr++;
c1 = getc(file1);
c2 = getc(file2);
if (c1 == c2) {
if (c1 == '\n')
line++;
if (c1 == EOF) {
if (eflg)
return (1);
return (0);
}
continue;
}
getc
システムコールを使用すると、read
なぜ遅いのですか?
答え1
getc()
getc() は読み込みデータを返す前にバッファリングするので 。への呼び出しは、カーネルで行うことが多いため、通常の関数呼び出しよりも完了するのに時間がかかるシステム呼び出しread()
です。read()
カーネル空間に入ったら、スタックを変更し、すべてのコンテキストを保存し、割り込みをマスクとして処理し、一方で完了したらコンテキストを復元し、割り込みを行い、ユーザー空間スタックを再配置します。これがすでに利用可能なバッファリングされたデータがある場合、多くのオーバーヘッドを節約するため、getc()が好ましい理由です。
答え2
最終的にディスクの読み取りはブロック指向です。ディスクからシングルバイトを読み取るには、ハードウェアは最終的にバイトブロック(512、1024、またはいくつかの数字)を読み取り、すべてのバイトをバッファリングしてカーネルに渡します。ファイルのブロック0からファイルのバイト0を読み取り、いくつかの操作を実行してからファイルからバイト1を読み取ると、カーネルは最終的にファイルのブロック0を読み取ることができます。再びバイト2の場合、再びバイト3の場合。はい、カーネルとディスクドライブ自体の両方に潜在的なキャッシュがありますが、カーネルは多くのプロセスを処理するため、おそらくそうではありません。
呼び出しごとread()
に、CPUをユーザーモードからカーネルモードに変更する必要があります。メモリマップは少なくとも変更されます。おそらくあまり明白でない他のことがたくさんあります。これも時間がかかります。
システムread()
コールはCPUの状態を変更し、ディスクI / Oが必要な場合があります。getc()
ディスクブロック全体(またはそれ以上)がユーザースペースにバッファリングされる可能性があるため、512呼び出しによってgetc()
カーネルは単一のディスクブロックを読み取り、単一の状態変更を実行できます。見てみると、ディスク上のファイルまたはシステムコールの有効(ディスクブロック多重)サイズでなければならない定数stdio.h
マクロを見つけることができます。BUFSIZ
read()
write()