同步/异步,阻塞/非阻塞,及IO多路复用

1.同步与异步、阻塞与非阻塞

  • 同步:执行一个操作之后,等待结果,然后才继续执行后续的操作。
  • 异步:执行一个操作后,可以去执行其他的操作,然后等待通知再回来执行刚才没执行完的操作。
  • 阻塞:进程给CPU传达一个任务之后,一直等待CPU处理完成,然后才执行后面的操作。
  • 非阻塞:进程给CPU传达任务后,继续处理后续的操作,隔断时间再来询问之前的操作是否完成。这样的过程其实也叫轮询。

1.阻塞与非阻塞

进程/线程要访问的数据是否就绪,进程/线程是否需要等待

2.同步与异步

访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要 I/O 操作完成的通知,不需要主动读写数据,由操作系统内核完成数据的读写。
在这里插入图片描述
阻塞、非阻塞、多路IO复用,都是同步IO,异步必定是非阻塞的,所以不存在异步阻塞和异步非阻塞的说法。真正的异步 IO 需要CPU的深度参与

换句话说,只有用户线程在操作 IO 的时候根本不去考虑 IO 的执行全部都交给CPU去完成,而自己只等待一个完成信号的时候,才是真正的异步IO。所以,拉一个子线程去轮询、去死循环,或者使用select、poll、e-poll,都不是异步。

各种I/O模型的例子:

1. 阻塞IO, 给女神发一条短信, 说我来找你了, 然后就默默的一直等着女神下楼, 这个期间除了等待你不会做其他事情, 属于备胎做法。

非阻塞IO, 给女神发短信, 如果不回, 接着再发, 一直发到女神下楼, 这个期间你除了发短信等待不会做其他事情, 属于专一做法.

2.IO多路复用, 是找一个宿管大妈来帮你监视下楼的女生, 这个期间你可以些其他的事情. 例如可以顺便看看其他妹子,玩玩王者荣耀, 上个厕所等等. IO复用又包括 select, poll, epoll 模式. 那么它们的区别是什么 ?

  1. select大妈 每一个女生下楼, select大妈都不知道这个是不是你的女神, 她需要一个一个询问, 并且select大妈能力还有限, 最多一次帮你监视1024个妹子;
  2. poll大妈不限制盯着女生的数量, 只要是经过宿舍楼门口的女生, 都会帮你去问是不是你女神;
  3. epoll大妈不限制盯着女生的数量, 并且也不需要一个一个去问. 那么如何做呢? epoll大妈会为每个进宿舍楼的女生脸上贴上一个大字条,上面写上女生自己的名字, 只要女生下楼了, epoll大妈就知道这个是不是你女神了, 然后大妈再通知你;

上面这些同步IO有一个共同点就是, 当女神走出宿舍门口的时候, 你已经站在宿舍门口等着女神的, 此时你属于阻塞状态

3. 接下来是异步IO的情况
你告诉女神我来了, 然后你就去王者荣耀了, 一直到女神下楼了, 发现找不见你了, 女神再给你打电话通知你, 说我下楼了, 你在哪呢? 这时候你才来到宿舍门口. 此时属于逆袭做法

2.I/O多路复用

2.1 形成原因

如果一个I/O流进来,我们就开启一个进程处理这个I/O流。那么假设现在有一百万个I/O流进来,那我们就需要开启一百万个进程一一对应处理这些I/O流(——这就是传统意义下的多进程并发处理)。思考一下,一百万个进程,你的CPU占有率会多高,这个实现方式及其的不合理。所以人们提出了I/O多路复用这个模型,一个线程,通过记录I/O流的状态来同时管理多个I/O,可以提高服务器的吞吐能力

2.2 通过它的英文单词来理解一下I/O多路复用

I/O multiplexing 也就是我们所说的I/O多路复用,但是这个翻译真的很不生动,所以我更喜欢将它拆开,变成 I/O multi-plexing,字面上来看I/O multiplexing 就是将多个I/O凑在一起。就像下面这张图的前半部分一样,中间的那条线就是我们的单个线程,它通过记录传入的每一个I/O流的状态来同时管理多个IO。
在这里插入图片描述

2.2 实现原理

在这里插入图片描述

  1. 当进程调用select,进程就会被阻塞;
  2. 此时内核会监视所有select负责的的socket,当socket的数据准备好后,就立即返回;
  3. 进程再调用read操作,数据就会从内核拷贝到进程。
2.3 实现方式
2.3.1 select

1. select函数的调用过程

  1. 从用户空间将 fd_set 拷贝到内核空间;

  2. 注册回调函数;
  3. 调用其对应的poll方法;

  4. poll方法会返回一个描述读写是否就绪的mask掩码,根据这个mask掩码给fd_set赋值;
  5. 如果遍历完所有的fd都没有返回一个可读写的mask掩码,就会让select的进程进入休眠模式,直到发现可读写的资源后,重新唤醒等待队列上休眠的进程。如果在规定时间内都没有唤醒休眠进程,那么进程会被唤醒重新获得CPU,再去遍历一次fd;

  6. 将fd_set从内核空间拷贝到用户空间。

2.select函数优缺点

缺点:两次拷贝耗时、轮询所有fd耗时,支持的文件描述符太小
优点:跨平台支持

2.3.2 poll

调用过程和 select 完全一致

poll函数优缺点

优点:连接数(也就是文件描述符)没有限制(链表存储)

缺点:大量拷贝,水平触发(当报告了fd没有被处理,会重复报告,很耗性能)

2.3.3 e-poll

4.1 epoll的ET与LT模式

LT延迟处理,当检测到描述符事件通知应用程序,应用程序不立即处理该事件。那么下次会再次通知应用程序此事件。
ET立即处理,当检测到描述符事件通知应用程序,应用程序会立即处理。

ET模式减少了epoll被重复触发的次数,效率比LT高。我们在使用ET的时候,必须采用非阻塞套接口,避免某文件句柄在阻塞读或阻塞写的时候将其他文件描述符的任务饿死

4.2 epoll的函数调用流程

a. 当调用epoll_wait函数的时候,系统会创建一个epoll对象,每个对象有一个evenpoll类型的结构体与之对应,结构体成员结构如下。

rbn,代表将要通过epoll_ctl向epll对象中添加的事件。这些事情都是挂载在红黑树中。
rdlist,里面存放的是将要发生的事件

b. 文件的fd状态发生改变,就会触发fd上的回调函数
c. 回调函数将相应的fd加入到rdlist,导致rdlist不空,进程被唤醒,epoll_wait继续执行。
d. 有一个事件转移函数——ep_events_transfer,它会将rdlist的数据拷贝到txlist上,并将rdlist的数据清空。
e. ep_send_events函数,它扫描txlist的每个数据,调用关联fd对应的poll方法去取fd中较新的事件,将取得的事件和对应的fd发送到用户空间。如果fd是LT模式的话,会被txlist的该数据重新放回rdlist,等待下一次继续触发调用。

4.3 e-poll的优点

  1. 没有最大并发连接的限制;
  2. 只有活跃可用的 fd 才会调用callback函数;
  3. 内存拷贝是利用mmap()文件映射内存的方式加速与内核空间的消息传递,减少复制开销(内核与用户空间共享一块内存)

只有存在大量的空闲连接和不活跃的连接的时候,使用 e-poll 的效率才会比 select/poll 高 。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值