信号驱动IO:两次调用,两次返回;
IO复用:主要是select和epoll;对一个IO端口,两次调用,两次返回,比阻塞IO并没有什么优越性;关键是能实现同时对多个IO端口进行监听;
2、select / epoll
采用轮询的方法,效率较低;
相比之下epoll的优点:能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;
利用mmap()文件映射内存加速与内核空间的消息传递;
epoll的两种模式:ET和LT。
LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表。
ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认。
3、mmap() / munmap()
应用程序通过调用mmap()函数在内存栈和堆之间创建一个新的线性地址空间并和磁盘文件建立一一映射关系。通过访问该区域,就能实现对文件的IO操作;调用msync()函数,可把映射内存空间的脏页写回磁盘。
几个问题:mmap()何时结束:调用munmap()可以关闭存储映射;
mmap()映射的内存空间大小必须是虚拟页长度的整数倍:
进程终止时,系统会自动把脏页写回磁盘,并解除映射关系。所以即使应用程崩溃,系统同样会做这一操作;