APUE笔记(一):IO效率

本文探讨了APUE中关于IO效率的内容,通过实验展示了不同缓冲区大小对系统调用时间(sys)的影响,指出缓冲IO是对不带缓冲IO的优化,并提出了两个遗留问题:高效率IO选择和内核系统调用的流程。实验结果显示,缓冲区大小约为16384时,IO效率相对较高。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2011 -8-24 补充:

1、这里的缓冲不缓冲是针对用户进程而言,磁盘IO肯定会经过内核的高速缓冲,而标准IO呢也使用了缓存(类似我们程序中的BUFFER),如果在标准IO中直接调用系统调用的fsync呢,也不能把缓冲刷到磁盘或者输出中,因为BUFFER在标准IO的缓存中,这时候还需要标准IO的fflush将缓存刷到内核的缓存,然后再fsync才会有作用

2、我这里的例子也是有些问题,用了同样的文件,会不会直接就放到了系统缓存中下一次就不需要读取了(3.9后面也有提醒这个,没有注意)。然后再实验不同文本发现差不多

================分割线

这两天又看APUE,看了前三章,里面的IO、系统调用刚好不太明白。就调研了一番

代码如下:

#include "unistd.h"
//unistd 不带缓冲的io函数,需要自己设立缓冲区,调用系统库
#include "stdio.h"

#define MAXSIZE 16384 //20480 //10240  //32768 // 81920 //1//16384 //4096
/*
 * read write的返回值与参数。
 * read 参数为最大空间,返回已经读取的字节数
 * write 参数为想要写的字节数,返回实际写的字节书
 */
int main(int argc,char * argv[])
{
  char BUFFER[MAXSIZE];

  int n;
  
  while( (n= read(STDIN_FILENO,BUFFER,MAXSIZE)) > 0)
    if( write(STDOUT_FILENO,BUFFER,n) != n)
      printf("写错误\n");

  if( n<0 )
    printf("读错误\n");

  return 0;
  

}



shaw@xxxx $ time ./ne_io < ~/Ebook/apue2.pdf > ~/Ebook/apue3.pdf

缓冲区大小  1

real         0m35.791s
user 0m1.344s
sys         0m34.162s

缓冲区大小 81,920

real         0m0.040s
user 0m0.000s
sys         0m0.040s

缓冲区大小 32,768

real   0m0.039s
user 0m0.000s
sys         0m0.036s

缓冲区大小 20,480

real         0m0.037s
user 0m0.000s
sys         0m0.036s

缓冲区大小 16384

real         0m0.033s
user 0m0.000s
sys         0m0.032s

缓冲区大小 10240

real         0m0.043s
user 0m0.000s
sys         0m0.040s

缓冲区大小 4096

real         0m0.042s
user 0m0.000s
sys         0m0.044s


user + sys = total process  time

real =  prepare + block + process

所以大体通过sys 时间就能看出效率来,我的pc大约16384附近效率还算比较高


这里没用用到标准IO,牵扯到第一章里看的系统调用与C函数库的概念,顺带谈一谈自己的体会


unistd.h中展开read函数的模型

int read(int fd, char *buf, int n)
{
long __res;
__asm__ volatile (
"int $0x80"
: "=a" (__res)
: "0" (__NR_read), "b" ((long)(fd)), "c" ((long)(buf)), "d" ((long)(n)));
if (__res>=0)
return int __res;
errno=-__res;
return -1;
}

手动调用

_syscall3(int, read, int, fd, char *, buf, int, n)
很多c函数库中的函数名与系统调用的名称一样是因为该函数本身其实就是调用的系统调用,放到c函数库就是为了用户态的使用,而如果

库函数中没有,也可以通过_syscallN手动调用,当然能调用的前提是有系统调用的服务例程并且声明服务例程的入口地址

_syscallN的原型,当N=1时

路径:/usr/src/linux/include/asm-i386/unistd.h

#define _syscall1(type,name,type1,arg1) /
type name(type1 arg1) /
{ /
long __res; /
__asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" /
: "=a" (__res) /
: "0" (__NR_##name),"ri" ((long)(arg1)) : "memory"); /
__syscall_return(type,__res); /
}
过程:当应用程序经过库函数向内核发出一个中断调用int 0x80时,就开始执行一个系统调用。其中寄存器eax中存放着系统调用号,而携带的参数可依次存放在寄存器ebx、ecx和edx中,只能传递3个参数。

这里只是说的一点点的从应用程序的角度来看如何调用系统调用,对于系统内核层次的一些服务例程上的事情,等以后懂了再继续补充吧。


遗留问题:

1、缓冲的IO是对上文中不带缓冲的IO的优化,具体怎么实现后面马上就知道了,以后对于IO效率要求比较高的地方是使用不带缓冲IO适配自己的机器呢,还是说缓冲IO就能用。这个应该很快就能清楚

2、内核里系统调用的流程,以及怎么开放一些系统调用例程给应用使用。这个慢慢来把


参考:http://book.51cto.com/art/200812/103342.htm


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值