专栏首页服务端技术杂谈你应该知道的五种IO模型

你应该知道的五种IO模型

点击上方蓝色字体,选择“设为星标”

优质文章,及时送达

写在前面

linux操作系统包含了五种IO模型,各种上层编程语言或者网络编程框架的上层实现都是基于操作系统的这些IO实现来实现的。

五种IO模型主要围绕:阻塞IO,非阻塞IO,异步IO来展开。

IO的处理流程

对于一次IO操作,数据先拷贝到内核空间,之后从内核空间拷贝到用户空间,所以一次数据读取操作经过两个阶段:

1. 等待数据就绪

2. 数据从内核空间拷贝到用户空间

IO模型

阻塞IO

进程发起IO调用,一直等待数据就绪和数据拷贝阶段完成,处于阻塞等待挂起中。

阻塞IO

非阻塞IO

进程进行read操作时,如果数据没有准备好就返回,通过轮训方式反复调用内核问“有数据了没?”,如果数据准备好了则将数据从内核空间拷贝到用户空间,调用过程第一阶段非阻塞。

非阻塞IO

多路复用IO

多个连接(fd)sockedFd或者fd就属于一路,多路就是多个fd连接,通过一个select轮训多个IO判断是否有就绪事件,如果读事件准备好就进行数据读取,将数据从内核空间拷贝到用户空间,数据拷贝阶段仍然阻塞。

多路复用

信号驱动IO

进行发起读取事件调用后立即返回,当数据就绪之后会以信号的方式通知进程,之后进程再次发起读取操作,将数据从内核空间拷贝到用户空间,数据拷贝阶段仍然阻塞。

信号驱动IO

异步IO

以上几种IO在数据复制阶段仍然是同步的,所以都属于某种程度的同步IO不是真正的异步IO。异步IO是进程发起读取操作后立即返回,等数据就绪之后,内核会将数据直接从内核空间拷贝到用户空间,并通知进程数据已经OK。这样在数据拷贝阶段就不是同步的了,实现了真正的异步。

异步IO

IO模型对比

同步和异步IO的区别在于系统调用的recvfrom()方法是否阻塞。

Select&Poll&Epoll

由于异步IO在linux操作系统层面支持还有限,所以多路复用IO是大部分网络框架采用比较多的IO模型,其底层支持主要围绕select&poll&epoll实现。

epoll是linux2.6引入的新型一部IO多路复用技术,他的前辈是poll,所以我们现聊下poll。

在异步IO出现之前,所有IO都是同步的。由于IO操作较慢,所以会造成阻塞,浪费大量CPU时间,所以就非常低效,于是就出现了poll模型。

select

poll模型有两个函数:select和poll。

select的缺点在于受限于文件描述符的大小,一个进程默认控制在1024文件描述符内,在判断就绪文件描述符时,需要遍历所有文件描述符以找到就绪描述符,成本巨大。

poll

poll没有最大文件描述符大小限制,但是和select一样,只能监听到几个文件描述符就绪了,得遍历所有文件描述符获取就绪的IO。

1. 每次循环select都需要对fd指向的设备进行poll操作,如果fd非常多时,比如超多网络IO,就会显得非常低效,所以poll会限制每个select注册的最大文件数。

2. 在进行消息通知时,select采用的是内存拷贝的方式,也会影响IO效率。

poll函数需要设备驱动程序的支持,用户进程使用select对每个fd(文件描述符)对应的设备使用poll函数,查询每个fd是否有读写事件需要处理,如果有就会返回需要处理的事件的个数,如果没有就将select进程放到等待队列进行休眠等待直到超时或是被唤醒。这个唤醒是设备驱动实现的,每次有数据到达时,驱动程序就去check是否有进程在读写等待队列里,有就将其唤醒。

epoll

在poll模型中,select只能返回就绪的fd数量,用户进程还需要去对所有fd进行遍历才能处理事件。为了解决这些问题,就引入了epoll。

epoll没有最大描述符大小限制,通过回调机制,一旦某个文件描述符就绪了,就迅速激活这个文件描述符,当进程下一次调用epoll_wait()时候便得到了通知。

epoll对poll的数据结构进行了增强,允许用户传入自定义的数据结构,这样可以快速定位事件位置了。所以在大量空闲连接的时候,epoll效率就要高很多。

poll和epoll都采用轮训方式实现异步IO,并未实现基于中断达到真正的异步,所以这种异步只是Non-Blocking IO,并不是真正的异步IO。

春哥叨叨实验室

本文分享自微信公众号 - 春哥叨叨(chungedaodao),作者:春哥大魔王

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 分布式概念-中心化副本控制机制

    前面的文章提到过副本是分布式系统中提升数据可用性,数据容错性,以及读吞吐的主要方式,对于多个副本数据一致性处理就是比较复杂且重要的话题。

    春哥大魔王
  • 简单理解reactor和proactor

    reactor是关心就绪事件,比如可读了,就通知你,就像epoll_wait 。proactor关心的是完成比如读完了,就通知你。

    春哥大魔王
  • IO模型梳理-从操作系统到应用层

    IO模型是编程语言和软件开发中重要的知识。本篇从IO模型这个切入点横向梳理了从操作系统到应用层IO模型相关知识。考虑到技术本身具有横向迁移的特点,也可以帮助大家...

    春哥大魔王
  • 【Java小工匠】JavaNIO-基础概念

    阻塞与非阻塞主要是程序等待消息通知时的状态角度来说的。阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。

    Java小工匠
  • python并发编程

    py3study
  • python之IO多路复用

      为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。

    py3study
  • Linux IO 概念(2)

    在上一篇IO底层的概念中杂合了很多模糊的概念,受知识水平的限制,只是从网上抄了很多过来.从linux一切皆文件的设计哲学,介绍了文件描述符,从进...

    用户3033338
  • IO - 同步,异步,阻塞,非阻塞

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,...

    后端技术探索
  • IO - 同步,异步,阻塞,非阻塞

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,...

    后端技术探索
  • Linux中IO多路复用机制

    之前的面试有问到主线程在 ActivityThread 里初始化 Looper 后调用了 Looper.loop() 这个死循环为什么不会阻塞主线程,当时回答因...

    萬物並作吾以觀復

扫码关注云+社区

领取腾讯云代金券