+ -
当前位置:首页 → 问答吧 → 【提问】问一个关于用AIO库改善文件i/o性能的问题

【提问】问一个关于用AIO库改善文件i/o性能的问题

时间:2011-01-05

来源:互联网

本帖最后由 almeydifer 于 2011-01-05 20:58 编辑

各位,本人现在遇到了一个实际的问题(属于应用层):

1.一个第三方的应用程序首先用O_DIRECT标志位打开了一个比较大的镜像文件,大约是8GB。

2.此时我因为我某种需要,将该应用程序的写请求全部截获,并且存放在自己设计的一个缓存中,每一个写操作的相关的脏数据存放在一个结构体里,不同的写操作的结构体之间用链表来相连接。

3.在某个时刻,我需要重新调用write操作,将截获的写请求重新刷入磁盘中盖镜像文件对应的位置。

现在问题来了,如果直接调用write的话,非常慢,因为此文件使用O_DIRECT标志位打开,

所以呢,我想利用AIO,也就是Linux提供的异步I/O库来提升其刷入磁盘的性能,也就是写性能。我现在的问题代码片段如下:
  1. struct aiocb my_aiocb;
  2.        
  3. bzero( (char *)&my_aiocb, sizeof(struct aiocb) );
  4.        
  5. my_aiocb.aio_fildes = prv->fd;

  6. list_for_each(_s, this_list){
  7.                 p = list_entry(_s, page_node_t, list);
  8.                 my_aiocb.aio_buf = malloc(p->size + 1);
  9.                 my_aiocb.aio_nbytes = p->size;
  10.                 my_aiocb.aio_offset = p->pageAddr;

  11.                 aio_write(&my_aiocb);
  12.         }
  13.        
  14.         while ( aio_error( &my_aiocb ) == EINPROGRESS );

  15.         return 1;
复制代码
中间那个list_for_each是将我前面提到的脏数据列表进行一个遍历,以刷新我所有缓存过的脏数据。
p是链表当中的结构体,pageaddr是我截获的写请求对应的offset,size是我截获的写请求对应的size
p当中还有个mybuf成员变量,用来缓存我截获的脏数据本身。
现在的问题是我感觉这个用法不大对劲,因为很可能我的用法不正确,
第一个问题是:性能几乎没有什么提高;
第二个问题是:狂占用内存,

各位如果有相关经验的话,恳请有劳指导一番。

作者: almeydifer   发布时间: 2011-01-05

第二个问题:aio_buf的内存为什么要malloc呢?用完free了吗?

第一个问题:为什么aio_write要比write性能高?
我的理解是:
现在要做的事情是把数据写入磁盘,性能的瓶颈在于写磁盘。不管使用哪种系统调用,需要写的数据都是一样多的。那么aio_write的性能又能比write高多少呢?
不过,write是阻塞的,只能提交一块、等待写入磁盘、再提交下一块。而aio_write是不需要阻塞的,可以连续的把所有请求都提交了,再一起等待。这有什么好处呢?多次aio_write提交的请求就有可能得到合并,而如果请求得到合并,写盘效率势必会提高(请求合并减少了磁盘寻道的次数,而磁盘寻道又是写盘的瓶颈所在)。
那么,什么情况下两个请求能被合并呢?两个条件,一是两个请求的内存连续、二是两个请求的磁盘位置连续。这两个条件在LZ的测试代码中能满足吗?第一,内存连续的可能性不大,因为aio_buf是malloc出来的,malloc的内存是对齐的,且内存与内存之间还可能夹杂很多控制信息;而第二点,磁盘位置是否连续更是不可知的。所以,请求能够被合并的可能性实在很小。

作者: kouu   发布时间: 2011-01-05