非阻塞IO原理和特性
下文所说的IO,包含IO就绪和IO操作
epoll 是一种Linux下的IO模型,是同步非阻塞的一种,也是当前比较流行的IO模型。
Linux下IO模型大致可以分为:同步阻塞、同步非阻塞、异步。
普通的非阻塞IO是各个IO自行盲询自己的IO是否就绪,而IO复用则是以一个系统调用来完成所有IO是否就绪的轮询,如果就绪则执行IO操作。
事件驱动是IO复用的一种升级版本,IO复用是轮询所有的IO。
而事件驱动是只处理已经就绪的IO,首先开启socket信号驱动的功能(将socket放到epoll文件系统里file对象对应的红黑树,并在内核终端处理程序中注册回调函数),当网卡检测到某个socket有数据来到时,内核就会将socket放入IO就绪队列,并从网卡拷贝数据到内核。
IO复用的缺点:
单线程能轮询的文件描述符有限1024;
需要轮询所有的IO,如果当前IO事件很多,但是就绪的非常少,那么会导致效率下降;
事件驱动则可以解决上述两个缺点,没有文件描述符的限制(通常都非常大,比如2G内存的机器都有655350);只处理已经就绪的IO,可以过滤掉不活跃的IO轮询带来的损失。
同时使用mmap(内存映射)的方式,来减少IO数据从内核-用户控件的拷贝。
MMAP介绍:
1、用户空间、内核空间都是不能直接访问设备的物理地址
2、内核空间如果要访问设备的物理地址,需要先映射物理地址到内核的虚拟地址(页缓存)上,以后驱动程序访问这个虚拟地址
3、用户空间只能通过系统调用访问映射好的内核虚拟地址(页缓存)
这上面会有2次数据拷贝,硬件和内核空间,用户空间和内核空间。
而MMAP的目的是将2次拷贝转换为1次拷贝,节约拷贝数据带来的消耗。
将物理地址映射到一块内存,应用程序(用户区域)可以直接访问这块内存。
事件驱动的缺点:
如果各个IO都比较活跃,那么IO复用的全轮询也不会有太多的性能损失,但是注册socket驱动事件却会带来一些负担。