readを使った読み込みではバッファサイズを多めにしていたのでfgetcよりも早くファイルが読めました。サイズをいろいろ変えて時間を確認してみます。
このプログラムを使います。
takk@deb9:~/tmp$ cat -n readwrite.c 1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 7 int main(int argc, char* argv[]) 8 { 9 char buf[1000]; 10 int fd; 11 int size,bufsize; 12 bufsize=atoi(argv[1]); 13 fd = open ("test.dat", O_RDONLY); 14 while(1){ 15 size = read(fd, buf, bufsize); 16 if(size == 0)break; 17 write(1,buf,size); 18 } 19 close(fd); 20 return 0; 21 } takk@deb9:~/tmp$
ついでにtest.datが1Gは大きすぎて待ち時間が長くなるので、100Mぐらいのデータに作り直し。
takk@deb9:~/tmp$ rm test.dat takk@deb9:~/tmp$ truncate -s100M test.dat
バッファサイズを指定できるプログラムをビルドします。
takk@deb9:~/tmp$ gcc readwrite.c takk@deb9:~/tmp$
最初は1000Byte。
takk@deb9:~/tmp$ time ./a.out 1000 >/dev/null real 0m0.173s user 0m0.004s sys 0m0.044s takk@deb9:~/tmp$
次に100Byte。10分の1にしたのですが、時間は10倍にはなってません。
takk@deb9:~/tmp$ time ./a.out 100 >/dev/null real 0m0.820s user 0m0.044s sys 0m0.220s takk@deb9:~/tmp$
さらに10分の1。それなりに時間がかかるようになってきました。
9倍ぐらいです。
takk@deb9:~/tmp$ time ./a.out 10 >/dev/null real 0m7.277s user 0m0.348s sys 0m2.052s takk@deb9:~/tmp$
元のバッファサイズ1000Byteとくらべて、1Byteは、1000分の1でも、処理時間は1000倍以上かかってます。バッファは大切ですね。
takk@deb9:~/tmp$ time ./a.out 1 >/dev/null real 1m9.033s user 0m3.580s sys 0m19.316s takk@deb9:~/tmp$
さて、前回のfgetcを使ったプログラムですが、処理時間はこのぐらいです。fgetcは、バッファを使った読み込みらしいので速いです。
takk@deb9:~/tmp$ time ./b.out > /dev/null real 0m3.789s user 0m1.220s sys 0m0.028s takk@deb9:~/tmp$
readによる読み込み(20Byteバッファ)と同じぐらいの時間になります。
takk@deb9:~/tmp$ time ./a.out 20 >/dev/null real 0m3.676s user 0m0.188s sys 0m1.016s takk@deb9:~/tmp$
fgetcで20Byteぐらいのバッファになってるということでしょうか。
気になるのでソースを探します。glibcから。
たいてい関数名.cなので、感で検索。
takk@deb9:~/src/glibc-2.24$ find -name 'fgetc.c' takk@deb9:~/src/glibc-2.24$
見つかりません。
grepにします。
takk@deb9:~/src/glibc-2.24$ grep -r fgetc.c ChangeLog.6: * libio/fgetc.c: Use _IO_cleanup_region_start and ChangeLog.6: * libio/fgetc.c: Avoid a warning by casting _IO_funlockfile for ChangeLog.6: * stdio/fgetc.c: Likewise. ChangeLog.6: * libio/fgetc.c: Use __libc_cleanup_region_* macros instead ChangeLog.7: * libio/fgetc.c: Likewise. ChangeLog.7: * stdio/fgetc.c: Likewise. ChangeLog.9: * libio/fgetc.c: Removed. ChangeLog.13: * stdio/fgetc.c: File removed. ChangeLog.8: * libio/fgetc.c: Call _IO_cleanup_region_end with 0 and call ChangeLog.5: * libio/clearerr.c, libio/feof.c, libio/ferror.c, libio/fgetc.c, ChangeLog.5: libio/ferror.c, libio/fgetc.c, libio/filedoalloc.c, libio/fileno.c, takk@deb9:~/src/glibc-2.24$
ChangeLog.13に、fgetc.cがRemoved.とあります。結構前に削除されているようです。
面倒なので、gdb動かします。
(gdb) b main Breakpoint 1 at 0x7d8: file fgetcfputc.c, line 7. (gdb) r Starting program: /home/takk/tmp/b.out Breakpoint 1, main () at fgetcfputc.c:7 7 fp = fopen("test.dat","r"); (gdb) n 8 while((c=fgetc(fp)) != -1){ (gdb) s _IO_getc (fp=0x555555756010) at getc.c:34 34 getc.c: そのようなファイルやディレクトリはありません. (gdb)
getc.cというファイルの_IO_getcという関数でした。
続く
コメント