美文网首页
简单理解IO模型

简单理解IO模型

作者: lingguo610 | 来源:发表于2018-12-14 15:38 被阅读0次

    网上那些同步、异步、阻塞、非阻塞概念容易弄得很混乱。

    以我的理解,只要知道原理即可,没必要为了一些概念弄得很混乱。

    首先,要明白IO模型的用处是:用来从IO读取、或者写入数据。

    以IO读取为例,有两个阶段:

    1、阶段一,等待内核准备好数据;

    2、阶段二,将数据从内核区拷贝到用户区。

    以下对5种IO模型分别作简单介绍。

    1、最简单的方法,告诉内核需要哪些数据,然后等待,直到有了数据之后,从内核区拷贝到用户区,也就是所谓的阻塞IO。

    实现方法:recvfrom

    2、告诉内核需要哪些数据,不等待,过一段时间去检查下,是否有数据,有则拷贝,没有则继续等待检查,这就是非阻塞IO。

    实现方法:recvfrom+nonblock

    3、同时监视多个IO端口,只要有数据就处理。这就是IO多路复用。

    实现方法:select 、poll或者epoll

    4、告诉内核需要哪些数据,既不等待,也不轮询,等到有数据后,内核主动通知,应用程序自己去拷贝,这就是信号驱动IO。

    5、和信号驱动很像,只不过内核有数据后,并将数据从内核区拷贝到用户区,再通知应用,也就是异步IO。

    方法:aio_read

    目前,用的最多是IO多路复用。

    对IO多路复用做个简单介绍。

    我们都知道IO多路复用,有三种类型,分别是select, poll, epoll

    1、select

    int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *excepset, const struct timeval *timeout);

    返回值:就绪描述符的数目,超时返回0,出错返回-1

    缺点:

    对待测试的描述符个数有限制,最大1024

    每次返回后,对readset、writeset、excepset采用轮询的方式判断是否有就绪数据,效率低

    每次调用select,都会将readset、writeset、excepset从用户区拷贝到内核区,同样,返回时,又会将三个数据结构从内核区拷贝到用户区,大量的空间复制,效率低

    2、poll

    int poll(struct pollfd *fds, unsigned int nfds, int timeout);

    poll是对select的改进。

    改进点:没有最大个数的限制。

    select的其他缺点依然存在。

    3、epoll 

    int epoll_create(int size);

    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对select存在的几个缺点分别有改进。

    轮询的方式改为:wait事件返回后, 返回值是需要处理的事件数目,并且将就绪事件存放在events中,避免对非就绪fd的轮询。

    大量内存复制改为:由原来一个接口改为三个接口,并只在接口epoll_ctl才将内容拷贝到内核,避免每次查询都拷贝。并且,不管是epoll_ctl的用户区拷贝到内核区,还是epoll_wait的内核区拷贝到用户区,都采用共享内存技术。

    epoll还有一个优点,支持边缘触发。

    所谓边缘触发,就是当描述符从未就绪变为就绪状态时,内核通过epoll告知应用,应用如果不处理,则下次内核不会告知这个变化。

    相关文章

      网友评论

          本文标题:简单理解IO模型

          本文链接:https://www.haomeiwen.com/subject/npdghqtx.html