先确定一下范围,我们讨论的都是网络IO,现阶段计算机早已经从CPU密集型转换成网络IO密集型,所以网络io的类型对于服务响应而言更重要。
依据Unix的IO分类,网络IO分为五类
可见另一篇文章
其中:第一阶段主要用来区分是否是阻塞IO
进行一个IO操作之后,无论是否有数据、是否就绪,是否会立刻返回而不阻塞用户进程的逻辑。
当用户进程发出read操作时,如果kernel中的数据没有准备好,不会block用户进程,而是返回一个EAGAIN err。从用户的角度而言,发起一个读操作,不需要等待,马上得到了一个结果。
一旦kernel的数据准备好了,收到用户进程的一个systemcall,就会马上把数据拷贝到用户内存,然后返回。
第二阶段,内核将数据拷贝到用户空间是否是同步进行的,决定是否是异步IO;除了aync IO以外其他都是同步的IO模型。
IO多路复用实际就是select/poll/epoll这些多路选择器,使用一个线程同时监听多个文件描述符(fd_set), I/O事件,阻塞等待并且在某个文件描述符可读写时收到通知。linux在处理网络IO连接时的优化,复用的不是I/O连接,而是复用的是线程,让一个线程处理多个连接。
选择器
运行逻辑
特点
缺点
select
1.最大并发数限制; 2.每次调用select,需要把fd_set集合拷贝到内核态;3.性能衰减严重
poll
poll与select类似,只是没有最大并发数限制
epoll
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
// 和 select 紧密结合的四个宏:
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
运行逻辑
fd_set如果是1 字节byte, 1byte = 8bit,每一个bit可以表示一个文件描述符fd,则1byte的fd_set最大可以对应8个fd
特点
缺点
epoll是Linux Kernel 2.6之后引入的IO事件驱动技术,本质上还是一个线程处理所有链接的等待消息准备好IO事件。但是 当数十万的并发连接存在时,可能每一毫秒猪油数百个活跃的链接,同时其余数十万连接在这一毫秒是非活跃的,而select&poll的使用方法是 返回的活跃链接 == select(全部带监控的连接)
高频调用的接口是select()方法,而这个方法任何轻微的效率损失都会被高频两个字放大。epoll解决了这个问题.
#include <sys/epoll.h>
int epoll_create(int size); // int epoll_create1(int flags);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
epoll的工作原理如下图:
手机扫一扫
移动阅读更方便
你可能感兴趣的文章