原文: http://blog.sina.com.cn/s/blog_4d6f62190100gtxw.html
异步操作,就我个人理解而言,是指一个单一事务的操作过程中,不会因为由于事务中的单个慢操作而堵塞事务的关键路径,从而影响处理的整体性能。从一个老外 的一篇文章中,看到了他对阻塞以及异步的整体理解,从这个理解出发,阻塞和异步互不冲突,同步的操作可以是阻塞的也可以是非阻塞的,异步的操作也可以是阻 塞或者是非阻塞的。
同步以及阻塞与否,对象涉及到了调用者进程以及被调用数据读取函数。
阻塞 非阻塞
-------------------------------------
同步 | read/write | read/write |
| (block) | (no block) |
-------------------------------------
异步 | IO多路复用 | AIO |
| | |
-------------------------------------
同步的阻塞操作:同步操作指的调用进程调用数据读取函数后,不能立即返回,必须等待对应数据读取函数获得数据后才能继续往下执行;阻塞的意思是指数据读取 函数如果不能立即获得数据而阻塞在该调用上。
同步的非阻塞操作:这种情况下,如果数据读取函数不能立即获得数据,将会立即返回,不会由于该函数的调用而阻塞对应的进程,后续调用进程必须主动再次调用 对应数据读取函数,再次尝试获取数据。
异步阻塞操作:这里的阻塞实际上是针对调用进程来说的,虽然IO多路复用可以实现事件的通知,但是调用进程仍旧需要主动查询对应的多路复用之内的事件,如 果没有事件发生,则会阻塞在该查询操作上。
高级的异步非阻塞操作来了,那就是大名鼎鼎的aio,aio是linux2.6以上内核中的一个属于realtime lib的调用接口组,所有对数据读取函数的调用都不会阻塞对应的调用上,同时也不需要调用进程主动地查询数据读写的状况,而是采用进程内的信号通知机制或 者预先注册的线程回调函数将数据ready事件通知给调用主进程。
可惜的是
Linux Kernel 2.6提供了对AIO的有限支持——仅支持文件系统,而表面上的异步IO也仅仅是libc的模拟而已,性 能上也没有什么优势。
代码示例如下:
#include <aio.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
struct aiocb * cb[2];
//The signal number to use.
#define SIG_AIO SIGRTMIN+5
//Signal handler called when an AIO operation finishes
void aio_handler(int signal, siginfo_t *info, void*uap)
{
int cbNumber = info->si_value.sival_int;
printf("AIO operation %d completed returning %d/n",
cbNumber,
aio_return(cb[cbNumber]));
}
int main(void)
{
struct sigaction action;
//Create a buffer to store the read data
char * foo = calloc(1,20);
//Set up the signal handler
action.sa_sigaction = aio_handler;
action.sa_flags = SA_SIGINFO;
sigemptyset(&action.sa_mask);
sigaction(SIG_AIO, &action, NULL);
FILE * file = fopen("bar", "r+");
//Allocate space for the aio control blocks
cb[0] = calloc(1,sizeof(struct aiocb));
cb[1] = calloc(1,sizeof(struct aiocb));
//Somewhere to store the result
cb[0]->aio_buf = foo;
cb[1]->aio_buf = foo + 10;
//The file to read from
cb[0]->aio_fildes = fileno(file);
cb[1]->aio_fildes = fileno(file);
//The number of bytes to read, and the offset
cb[0]->aio_nbytes = 10;
cb[1]->aio_nbytes = 10;
cb[0]->aio_offset = 0;
cb[1]->aio_offset = 10;
//The signal to send, and the value of the signal
cb[0]->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb[0]->aio_sigevent.sigev_signo = SIG_AIO;
cb[0]->aio_sigevent.sigev_value.sival_int = 0;
cb[1]->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb[1]->aio_sigevent.sigev_signo = SIG_AIO;
cb[1]->aio_sigevent.sigev_value.sival_int = 1;
aio_read(cb[0]);
aio_read(cb[1]);
while(1){sleep(1);}
sleep(1);
}