[转帖]Unix编程_-_IO_小结_VMware, Unix及操作系统讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  VMware, Unix及操作系统讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3167 | 回复: 0   主题: [转帖]Unix编程_-_IO_小结        下一篇 
晶晶
注册用户
等级:少校
经验:1086
发帖:89
精华:0
注册:2012-11-8
状态:离线
发送短消息息给晶晶 加好友    发送短消息息给晶晶 发消息
发表于: IP:您无权察看 2012-11-13 16:10:23 | [全部帖] [楼主帖] 楼主

Unix编程 – I/O

1 关于 Unix I/O

系统为每个进程都维护一份打开文件的文件列表,表中每个元素的内容包括指向文件备份inode的指针以及元数据(文件状态、位置等)。

该列表由文件描述符来索引,文件描述符是非负数,一般一个进程的上限是1024-1是非法值。

子进程会得到父进程的一份文件列表的拷贝,也就是说,则进程继承了父进程多有打开的文件状态。

2 Unix 提供的基本I/O

2.1 常用函数

作为Unix系统提供的基本系统调用,主要有以下接口,都是基于文件描述符的:

l open / read / write / close / lseek
l fsync / fdatasync
l poll / select


l 其他,包括文件截短等

2.2 主要接口的关键特性及注意事项

2.2.1 read


l 首先,我们要考虑返回值。

1. 正常情况下,返回length 为预期读取的数据长度。

2. 当0 < length < 预期长度,可能有以下几种情况:系统调用被中断抢占,发生一般错误,读到预期长度前就已经读到了EOF

3. 返回 ,表示读到了EOF

4. 返回 -1,表示发生了错误。

l 为了保证读到所有数据,应当进行特殊处理

用一个循环来进行read调用,每次读出的长度进行累加,直到达到预期长度。当然如果中间发生了错误,应当参见下一条进行处理。

l 当发生错误时,我们需要检查errno

1. EINTR,表示被中断打断,应当重新读取

5. EAGAIN,表明由于没有数据读而使得read调用被阻塞,应当在稍后重新读取

l 关于非阻塞读

这里的非阻塞,不是指阻塞系统调用,而是当没有数据可读的时候,进程不会因此而挂起,导致无法处理其他的指令。

应当由应用程序来保证当read调用被阻塞后,能够在稍后重新唤醒。

2.2.2 write


l 首先,我们也是要考虑到几种特殊情况

1. 部分写,这个和read类似,需要用循环来保证

6. 追加写,这个是表明始终在文件末尾写入,(多进程,日志)

7. 非阻塞写,通常不会出现,处理和非阻塞读类似

l 重要的是,要明确write的行为

write实际上是将用户缓存空间中的数据,写入了内核缓存,这时调用就返回成功了。而其实数据并没有立刻就写回磁盘。

这样处理的原因,一方面有可能提高后续读取数据的处理效率,另一方面系统是为了提高写回文件时的处理效率,通过内核缓存一定的数据然后一次性写回,避免磁头的多次寻轨(参见缓冲I/O 即 Stdio

当然这就需要考虑同步的问题,而且何时写回文件也需要考虑其策略,一般会定义一个缓存在内核中的生命期。

2.2.3 fsync / fdatasync


2个调用是为了确保内存中的脏数据与磁盘上的进行同步。前者不仅进行数据同步,还会同步文件的元数据。

2.2.4 poll / select


l I/O多路复用的特点

首先,我们监听多个描述符,当没有描述符准备好时,处于休眠状态;其次,一旦有描述符准备就绪,将唤醒,并根据事件类型进行处理;最后,返回第一步。

l select 与 poll的优劣

select比较传统,使用比较广泛(习惯、可移植性),麻烦的地方在于需要每次都设置描述符集(调用FD_x宏),计算最大描述符等。且select是对max_fd以下的所有描述符进行探测,当该值很大的时候,十分影响效率。

poll因为将被监听的描述符集合与就绪的描述符集合进行了区分,因此不需要每次都进行设置。且每一个pollfd中负责一个对象,可以由用户来指定需要探测的描述符。但是poll移植性不佳。

两者有共同的问题就是,系统都需要监听所有的描述符,当描述符列表很大的时候,这个行为将会十分影响效率。这个问题在epoll那里得到了很好的解决。

2.3 基本I/O的特性,优劣

首先我们要清楚的是,Unix的一个核心理念:everything is a file. 那么我们在需要进行I/O的时候,就自然有上面列出的各种操作:打开、定位、读、写、关闭以及获取文件信息等。

但我们通过基本I/O的接口可以发现,这些调用都是直接与磁盘文件在打交道。我们知道,磁盘的读写与内存相比是慢了一个数量级以上的,如果频繁的进行这样的系统调用,那么系统的效率将势必十分低下。

这就催生了缓冲I/O的出现,我们平时使用的标准c提供的stdio,即为一种应用广泛的缓冲I/O

3 标准c提供的缓冲I/O(即Stdio

3.1 缓冲 I/O 的原理

关于缓冲I/O,很重要的一点,就是要搞清楚缓冲区是位于用户区的,而前面提到的基本I/O的缓冲区则属于内核。

当调用进行缓冲读时,实际上的行为是首先调用read,从内核缓冲区将数据拷贝到用户缓冲区,再通过stdio的接口比如fgetc,将用户缓冲的数据拷贝到指定的缓存。缓冲写的过程则相反。

3.2 常用函数

l fopen / fdopen / fclose / fseek
l fread / fgetc / fgets
l fwrite / fputc / fputs


l 其他,包括 fflush / feof / fileno / flockfile / funlockfile 

3.3 主要接口关键特性及注意事项

3.3.1 二进制读写 fread / fwrite


这里需要注意的主要就是,因为变量的大小、字节序、填充、对齐等因素,通常一个程序写的二进制文件,只有该程序可以读取。

不同程序、同一程序的不同版本(包括运行环境不同)都可能是不能读取的。

3.3.2 fseek


这个函数的功能和lseek一样,都是进行定位,但前者是对fd进行操作,后者是对fp进行操作。尤其要注意的是,fseeklseek不应当混用,其结果是未定义的。

3.3.3 fflush


将所有流中的数据写入内核缓冲区。一般会和fsync连用,表明首先将用户缓冲区的内容冲入内核,然后将内核缓冲区的数据同步到磁盘。

3.4 缓冲I/O是如何提升性能的

首先,它有自己的用户缓冲区,将数据读入后,不再需要频繁的调用系统调用从内核缓冲区读写数据。这就降低了系统调用的开销。只有当必须与磁盘等介质交互时,才会进行系统调用。

第二,通过设置缓冲区,以及设备块的大小,并且一次性读/写块大小的整数倍数据时,是在物理上更高效的,原因有2。其一,一次性读写相当的数据可以减少系统调用次数,其二,按照整块的方式来读写,性能更高。

3.5 缓冲I/O的不足

l 线程安全问题 

l 部分函数不够安全,比如 gets

l 数据的多次拷贝问题

后者的问题,我们可以在高级I/O中找到更好的选择

4 高级I/O

4.1 散布/聚集 I/O   readv / writev

这里的v,是向量的意思,顾名思义,这类I/O实际上有点就在于,能够一次性的对与分散在多个不连续的缓冲区中的数据进行读写,减少了大量的系统调用。

从另一方面来将,避免了若干个连续的线性I/O,也实现了I/O的原子性。

4.2 更高级的多路复用 epoll

能够逐个描述符的指定需要监听的事件,系统也将只监听被指定的描述符,大大提高了效率。

4.3 存储映射 mmap / mummap

这种方式,是直接将文件的某一段,按照页为单位映射进内存,然后透明的进行读写。

优点有:读写映射文件,就像进行内存操作一样简单,不需要进行系统调用,也省略了多余的数据拷贝。

缺点有:必须按照整页为单位进行映射,导致可能会出现许多大小不一的碎片。

因此,处理较大文件、或大小为page size的整数倍的文件比较有优势。

4.4 文件I/O提示

通过提示内核将要对文件进行什么模式的I/O,内核将决定如何读取文件到内存,以此来在有限的内存的条件下,提高RAM的命中率,从而提高处理效率。

主要的模式有:一般,顺序,随机等。

对应的处理方式:少量预读,大量预读,不预读。

5 其他需注意的问题

5.1 关于I/O调度

为什么需要调度?因为如果按照程序的顺序进行系统调用,那么几乎是无法避免的要进行大量的seek操作,这将导致磁头进行大量的寻道,从而导致效率低下。

I/O调度器的功能就很显然了:将分布在多个I/O调用中的目标数据块进行排序,将临近的数据块一次性进行读写。即两个功能:合并、排序。

5.2 优化读请求

这里指的是内核从磁盘读取文件的算法,典型的有电梯算法,Dead-line算法等。重要性不言而喻。

那么为什么强调优化读请求?一般而言,读请求需要返回最新的数据,如果无法命中RAM,那么读请求在数据从磁盘中返回前会一直阻塞。

而写操作(缺省非同步)则不会引起这个问题,在短期内是不会发起人和I/O操作的。会出问题是在读写操作混合的时候。

5.3 优化I/O性能

重要性不用多说,那一般有哪些方法?

l 使用缓冲I/O

l 减少系统调用。(散布/聚集)

l 用户空间的I/O调度。(路径排序、inode排序、物理块排序,各有优劣)




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论