libaio实现参考
对于磁盘文件,文件的读取是同步的,导致线程读取文件时,属于阻塞状态。程序为了提升性能和磁盘的吞吐,程序会创建几个单独的磁盘读写线程,并通过信号量等机制进行线程间通信(同时带有锁);显然线程多,锁多,会导致更多的资源抢占,从而导致系统整体性能下降。
libaio提供了磁盘文件读写的异步机制,使得文件读写不用阻塞,结合epoll机制,实现一个线程可以无阻塞的运行,同时处理多个文件读写请求,提升服务器整体性能。下面是libaio+epoll的一个实现示例。
代码删除了变量初始化、异常判断等分支。
/* AIO的回调函数*/ void aio_callback(io_context_t ctx, struct iocb *iocb, long res, long res2) { /* 失败时-res为errorno;成功时,res为真正读取的字节数; iocb->u.c.buf为读取的内容*/ ··· } /* * 使用libaio和epoll,对同一个文件的若干个不同偏移位置发起异步读取请求, * 如对文件的偏移位置0、1024*1、1024*2、、1024*127发起总共128个异步读取请求(读取1024字节) */ int libaio_epoll_read_file() { efd = eventfd(0, EFD_NONBLOCK); fd = open(TEST_FILE, O_RDWR | O_CREAT | O_DIRECT, 0644); io_setup(8192, &ctx); for (int i = 0; i < NUM_EVENTS; i++) { posix_memalign(&buf, ALIGN_SIZE, RD_WR_SIZE); io_prep_pread(iocbs[i], fd, buf, RD_WR_SIZE, i * RD_WR_SIZE); io_set_eventfd(iocbs[i], efd); io_set_callback(iocbs[i], aio_callback); } io_submit(ctx, NUM_EVENTS, iocbs); epfd = epoll_create(1); epevent.events = EPOLLIN | EPOLLET; epevent.data.ptr = NULL; epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent); while (i < NUM_EVENTS) { epoll_wait(epfd, &epevent, 1, -1); read(efd, &finished_aio, sizeof(finished_aio)); while (finished_aio > 0) { r = io_getevents(ctx, 1, NUM_EVENTS, events, &tms); for (j = 0; j < r; ++j) { // 调用对应事件的回调函数,处理数据 ((io_callback_t)(events[j].data))( ctx, events[j].obj, events[j].res, events[j].res2); } } } }