什么是阻塞,非阻塞,异步同步,select,poll,epoll?今天我们用一遍文章解开这多年的迷惑。

首先我们想要通过网络接收消息,是这样的一个步骤。

  1. 用户空间向内核空间请求网络数据
  2. 内核空间把网卡数据读取到内核缓冲区
  3. 将内核缓冲区的数据复制到用户缓冲区

根据我们请求数据的情况不同,以及内核缓冲区到用户缓冲区的不同,分为了阻塞,非阻塞,异步同步的区别。

在《UNIX网络编程》一书中,总结归纳了5种I0模型:

  • 阻塞 I0 ( Blocking I0)
  • 非阻塞 I0 (Nonblocking I0)
  • I0多路复用(I0 Multiplexing)
  • 信号驱动I0 (Signal Driven I0 )
  • 异步I0 (Asynchronous I0)

阻塞IO

  1. 用户应用请求内核是否有新的网络数据
  2. 如果没有数据,就阻塞直到有数据到来
  3. 等待内核将数据拷贝到用户空间
  4. 用户应用处理数据

以上可以看出来,根据等待数据的方式不同,分为阻塞和非阻塞。

阻塞IO在请求内核数据的时候,没有数据就会一直阻塞直到获取数据。

非阻塞IO

  1. 用户应用请求内核是否有新的网络数据
  2. 如果没有数据,内核直接返回没数据,用户应用可以隔一段时间再来请求。
  3. 等待内核将数据拷贝到用户空间
  4. 用户应用处理数据

非阻塞IO在等待内核数据的时候,没有数据就会得到没数据的结果,应用可以进行其他动作。

同步IO

同步IO的主要看内核数据到用户空间的过程是同步进行的就是同步IO

异步IO

异步IO首先是非阻塞IO,区别在于成功标志的时机。异步IO连内核到用户态的数据拷贝都是异步的,直到数据拷贝完成,才会回调一个信号,通知一切已经准备完成。用户应用此时就可以直接处理结果了。

总结

阻塞非阻塞指的是在获取结果上是否会阻塞等待结果完成

同步异步指的是是否会参与IO读写,或者是等待读写成功的回调

redis的IO多路复用

如果是阻塞IO也就是BIO,那么在一个fd(文件描述符)没有数据的时候,就是阻塞一直等待,如果同时有多个fd,对于单线程来说,只能一直等第一个有数据,然后再接着处理第二个,效率很慢。

就像顾客点餐,要一直等到第一个人点完餐,后面的人才有机会。BIO也有个解决办法,一般是增加多线程,每个线程都维护一个fd,就相当于为每个顾客都添加一个点餐台。在fd足够多的情况下,会有大量的线程被创建,线程可是有上限的,开销也大(更多线程需要更多的内存空间)。

如果是非阻塞IO也就是NIO,会有顾客没点完餐,然后造成CPU一直在询问一直空转的情况。

因此引入了IO多路复用模型:利用单个线程来同时监听多个FD,并在某个FD可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源

文件描述符( File Descriptor) :简称FD,是一个从0开始递增的无符号整数,用来关联Linux中的一一个文件。在Linux

中,一切皆文件,例如常规文件、视频、硬件设备等,当然也包括网络套接字(Socket),

这时候每来一个顾客(FD),我们就会给他一个开关(注册进监听事件),一个服务员(一个线程)等待开关亮起(阻塞等待事件)。有顾客完成,就会按下开关,一定的频率下开关会亮起(事件通知),服务员会选取按下开关的一批人,给他们点餐(批量处理事件)。

IO多路复用的实现有select,poll,epoll,我们来看看他们的优缺点。

select

select是Linux中最早的I/O多路复用实现方案,并且windows操作系统上只支持select。这就是为啥window发挥不出redis的最大性能的一个原因。

select函数执行流程

  1. 用户空间创建fd_set,把需要监听的位置置1,比如 1,2,5
  2. 用户空间拷贝fd_set(注册的事件集合)到内核空间
  3. 内核遍历所有fd文件,并将当前进程挂到每个fd的等待队列中,当某个fd文件设备收到消息后,会唤醒设备等待队列上睡眠的进程,那么当前进程就会被唤醒
  4. 内核如果遍历完所有的fd没有I/O事件,则当前进程进入睡眠,当有某个fd文件有I/O事件或当前进程睡眠超时后,当前进程重新唤醒再次遍历所有fd文件
  5. 内核有事件产生,会把fd_set中有事件的位置保留为1,没有事件的位置擦除为0.
  6. 内核拷贝fd_set给用户空间
  7. 用户空间线程被唤醒,遍历fd_set为1的位置,确认是哪些fd有就绪事件,然后开始处理
  8. 用户空间处理完事件,再一次将要监听的fd_set设置为1,重复之前的监听动作

根据上面可以很清楚的看出整个执行流程在用户空间和内核空间的切换。

select函数的缺点

  • 单个进程所打开的FD是有限制的,通过 FD_SETSIZE 设置,默认1024
  • 每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
  • 每次调用select都需要将进程加入到所有监视socket的等待队列,每次唤醒都需要从每个队列中移除
  • select函数在每次调用之前都要对参数进行重新设定,这样做比较麻烦,而且会降低性能
  • 进程被唤醒后,程序并不知道哪些socket收到数据,还需要遍历一次

poll

poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的

poll运行流程

①创建pollfd数组, 向其中添加关注的fd信息,数组大小自定义

②调用poll函数,将pollfd数组拷贝到内核空间,转链表存储,无上限

③内核遍历fd,判断是否就绪

④数据就绪或超时后,拷贝pollfd数组到用户空间,返回就绪fd数量n

⑤用户进程判断n是否大于0

⑥大于0则遍历pollfd数组,找到就绪的fd

与select对比

  • select模式中的fd_ set大小固定为1024,而pollfd在内核中采用链表,理论上无上限.
  • 监听FD越多,每次遍历消耗时间也越久,性能反而会下降

poll还是没有解决需要遍历判断fd事件的方式,只是增加了监听数量,在fd很多的情况下,性能下降的更加严重

epoll

epoll可以理解为event pool,不同与select、poll的轮询机制,epoll采用的是事件驱动机制,每个fd上有注册有回调函数,当网卡接收到数据时会回调该函数,同时将该fd的引用放入rdlist就绪列表中。

当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户。

他主要有三个函数,epoll的执行流程

  1. 调用epoll_create创建一个eventpoll结构体,这个结构体有一个监听事件红黑色,和一个就绪链表(这个链表只会存放就绪fd,避免我们无效的遍历所有fd)

  1. 调用epoll_ctl向eventpoll中注册一个监听的fd,并且注册上fd对应事件的回调函数。

  1. 调用epoll_wait开始阻塞等待事件到来
  2. 内核将监听到的事件添加一份到就绪队列list_head

  1. 内核唤醒用户线程,并将就绪链表拷贝到用户空间

  1. 用户应用只需要关心这些就绪的fd事件,直接取出结构体里关联的回调函数进行回调即可处理事件。

对应的redis的server执行流程

  1. 调用epoll_create创建一个eventpoll结构体
  2. 调用epoll_ctl向eventpoll中注册一个监听连接的serverSocket,并关联上处理accept事件的函数
  3. 调用epoll_wait阻塞等待fd事件(等待客户端连接)
  4. 用户程序被唤醒,事件到来(现在只有连接事件)。根据生成的客户端的FD,调用epoll_ctl注册一个监听,并且关联上处理read事件的函数和处理write事件的函数。
  5. 继续调用epoll_wait阻塞等待fd事件(等待客户端连接或客户端命令执行请求)
  6. 用户程序被唤醒,事件到来(连接事件或者命令执行请求),假设是客户端执行请求事件,根据客户端的fd对应的read事件直接调用绑定的回调函数来处理,将结果再写回到fd缓存中。
  7. 继续调用epoll_wait等待accept,read,write事件。

epoll优点

  • EPOLL支持的最大文件描述符上限是整个系统最大可打开的文件数目, 1G内存理论上最大创建10万个文件描述符
  • 每个文件描述符上都有一个callback函数,当socket有事件发生时会回调这个函数将该fd的引用添加到就绪列表中,select和poll并不会明确指出是哪些文件描述符就绪,而epoll会。造成的区别就是,系统调用返回后,调用select和poll的程序需要遍历监听的整个文件描述符找到是谁处于就绪,而epoll则直接处理即可
  • select、poll采用轮询的方式来检查文件描述符是否处于就绪态,而epoll采用回调机制。造成的结果就是,随着fd的增加,select和poll的效率会线性降低,而epoll不会受到太大影响,除非活跃的socket很多

读事件很好理解,有一个读事件就立马处理请求,怎么理解写事件?

当socket 写缓冲区已满,假如设置了非阻塞I/O,应用程序调用send会返回EAGAIN,告诉应用程序写缓冲区已满,下次再来尝试调用,这时候就有一个尝试的时机问题,应用程序怎么知道socket 缓冲区可写呢?如果频繁调用send,会浪费CPU。这时候,epoll就排上用场了,对socket 设置写事件,并添加到 epoll中,应用程序调用epoll_wait,当该socket 的写缓冲有空余时,就返回对应的写事件,应用程序这时候就可以调用send,发送数据。

所以写事件是用来告诉程序,写缓冲是空余的。一般情况下fd都是有写事件的。但是在写缓冲区满了的时候,就会频繁触发写事件。所以我们可以一开始不监听写事件,直到发现数据量可能大于缓冲区,再监听写事件

参考:高效处理写事件

参考

select poll epoll

黑马多路复用视频

Redis的IO多路复用原理相关推荐

  1. IO多路复用原理(大白话,通俗易懂)

    IO多路复用原理 BIO NIO IO多路复用之select模型和poll模型 IO多路复用之epoll模型 Reactor模型 IO多路复用技术: 讲IO多路复用技术之前,我们得先了解NIO和BIO ...

  2. Redis单线程还是多线程?IO多路复用原理

    目录 专栏导读 一.Redis版本迭代 二.Redis4.0之前为什么一直采用单线程? 三.Redis6.0引入多线程 四.Redis主线程和IO线程是如何完成请求的? 1.服务端和客户端建立sock ...

  3. IO多路复用原理剖析

    (最近笔试遇到笔试题:select,poll,epoll都是IO多路复用的机制). I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应 ...

  4. redis 十一. IO 多路复用

    目录 一. 基础 select poll epoll 二. redis 与多路复用 一. 基础 首先知道一下五种io模型有个概念 Blocking IO: 阻塞IO NoneBlockin IO: 非 ...

  5. redis多路IO复用原理

    redids的IO多路复用例子: 1,2,3 三个人通过黄牛去买票,当1买的票没有时,1还可以干其他的事情,2和3一次类推,黄牛发现1的票有的时候再告知1去买票,此时1再去买票.即多路IO服用的意思是 ...

  6. Redis源码剖析(二)io多路复用函数及事件驱动流程

    作为服务器监听客户端请求的方法,io多路复用起到了不可忽略的作用,利用io复用监听的方法叫Reactor模式,在前一篇也提到过,使用io复用是现在常用的提高并发性的方法,而且效果显著. 通常io多路复 ...

  7. Redis IO多路复用理解

    IO多路复用在Redis中的应用 Redis 服务器是一个事件驱动程序, 服务器处理的事件分为时间事件和文件事件两类. 文件事件:Redis主进程中,主要处理客户端的连接请求与相应. 时间事件:for ...

  8. 09-Redis IO 多路复用

    目录 一 Redis 是单线程还是多线程? 二 为什么单线程的 Redis 性能很高? 三 什么是 IO 多路复用技术? 四 Redis 6.0 开始引入多线程? 一 Redis 是单线程还是多线程? ...

  9. IO模型、IO多路复用

    IO多路复用 基础概述 用户空间和内核空间 PIO与DMA 缓存IO和直接IO 缓存IO 优点 缺点 直接IO IO访问方式 磁盘IO 网络IO 磁盘IO和网络IO对比 Socket网络编程 客户端 ...

最新文章

  1. 服务的实例已在运行中_亚马逊首次把macOS引入云服务
  2. 卷积神经网络在自然语言处理的应用
  3. 进击的UI---------------------UIStepper(加减)
  4. QML和C ++之间的数据类型转换
  5. 系统工程师主要做什么_Filecoin运维工程师在做什么?
  6. oracle基本的操作
  7. 数据库敏感数据加密技术
  8. 上银驱动器使用手册_禾川伺服驱动器说明书
  9. 易打卡模板微信签到打卡小程序源码
  10. 用HTML5为你的网页添加音效(兼容Firefox 3.5+, IE 6-9, Safari 3.0+, Chrome 3.0+, Opera 10.5+)
  11. 网钛CMS采集插件-无需登陆自动采集发布插件
  12. mysql特性—自适应哈希索引AHI
  13. 《增长黑客》- 读书笔记(一)
  14. 使用SwipeRecyclerView配合下拉刷新出现Scrapped or attached views may not be recycled. isScrap:false isAttached:
  15. pip问题:Traceback (most recent call last):File “/home/coin/anaconda3/lib/python3.7/site-packages/pip/_
  16. 燕十八PHP全套视频
  17. 深度学习——注意力机制
  18. uni-app开发中,使用ThorUI中的图片上传,自定义接口返回数据修改
  19. 设计师必备特效生成器合集 2022背景快速制作指南
  20. NLP语料库构建(corpus)

热门文章

  1. 【证书】certbot 工具,自动 letencrypt 通配符证书自动续期(renew)
  2. ArcGIS中求多边形的“四至点”
  3. 【论文阅读】TranAD: Deep Transformer Networks for Anomaly Detection inMultivariate Time Series Data
  4. win10台式电脑连接蓝牙耳机
  5. html5 图片流,Html5之webcoekt播放JPEG图片流
  6. 数据可视化分析教学课件——FineBI实验册节选====风险分析
  7. 网页快照(图片)工具分享
  8. 一箭穿心的python代码
  9. HTML《传智播客学员档案》
  10. redhat6.5 centos6.5 FusionCompute下VNC花屏