概述

当我们要编写一个echo服务器程序的时候,需要对用户从标准输入键入的交互命令做出响应。在这种情况下,服务器必须响应两个相互独立的I/O事件:1)网络客户端发起网络连接请求,2)用户在键盘上键入命令行。我们先等待哪个事件呢?没有哪个选择是理想的。如果在acceptor中等待一个连接请求,我们就不能响应输入的命令。类似地,如果在read中等待一个输入命令,我们就不能响应任何连接请求。针对这种困境的一个解决办法就是I/O多路复用技术。基本思路就是使用select函数,要求内核挂起进程,只有在一个或多个I/O事件发生后,才将控制返回给应用程序。 --《UNIX网络编程》

mysql线程池,就是I/O多路复用的体现。

参考:https://blog.csdn.net/wangxindong11/article/details/78591308

一、I/O多路复用概述

I/O多路复用,I/O就是指的我们网络I/O,多路指多个TCP连接(或多个Channel),复用指复用一个或少量线程。串起来理解就是很多个网络I/O复用一个或少量的线程来处理这些连接。

多路复用的本质是同步非阻塞I/O,多路复用的优势并不是单个连接处理的更快,而是在于能处理更多的连接。

I/O编程过程中,需要同时处理多个客户端接入请求时,可以利用多线程或者I/O多路复用技术进行处理。

I/O多路复用技术通过把多个I/O的阻塞复用到同一个select阻塞上,一个进程监视多个描述符,一旦某个描述符就位, 能够通知程序进行读写操作。因为多路复用本质上是同步I/O,都需要应用程序在读写事件就绪后自己负责读写。

最大的优势是系统开销小,不需要创建和维护额外线程或进程。

  • 应用场景
  • 服务器需要同时处理多个处于监听状态或者多个连接状态的套接字
  • 需要同时处理多种网络协议的套接字
  • 一个服务器处理多个服务或协议

目前支持多路复用的系统调用有select, poll, epoll。


二、几种常用I/O模型

BIO

阻塞同步I/O模型,服务器需要监听端口号,客户端通过IP和端口与服务器简历TCP连接,以同步阻塞的方式传输数据。服务端设计一般都是 客户端-线程模型,新来一个客户端连接请求,就新建一个线程处理连接和数据传输

当客户端连接较多时就会大大消耗服务器的资源,线程数量可能超过最大承受量

伪异步I/O

与BIO类似,只是将客户端-线程的模式换成了线程池,可以灵活设置线程池的大小。但这只是对BIO的一种优化手段,并没有解决线程连接的阻塞问题。

NIO

同步非阻塞I/O模型,利用selector多路复用器轮询为每一个用户创建连接,这样就不用阻塞用户线程,也不用每个线程忙等待。只使用一个线程轮询I/O事件,比较适合高并发,高负载的网络应用,充分利用系统资源快速处理请求返回响应消息,是和连接较多连接时间I/O任务较短

AIO

异步非阻塞,需要操作系统内核线程支持,一个用户线程发起一个请求后就可以继续执行,内核线程执行完系统调用后会根据回调函数完成处理工作。比较适合较多I/O任务较长的场景。


三、select

监视多个文件句柄的状态变化,程序会阻塞在select处等待,直到有文件描述符就绪或超时。

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

可以监听三类文件描述符,writefds(写状态), readfds(读状态), exceptfds(异常状态)。

我们在select函数中告诉内核需要监听的不同状态的文件描述符以及能接受的超时时间,函数会返回所有状态下就绪的描述符的个数,并且可以通过遍历fdset,来找到就绪的描述符。

缺陷

  • 每次调用select,都需要把待监控的fd集合从用户态拷贝到内核态,当fd很大时,开销很大。
  • 每次调用select,都需要轮询一遍所有的fd,查看就绪状态。
  • select支持的最大文件描述符数量有限,默认是1024

四、poll

与select轮询所有待监听的描述符机制类似,但poll使用pollfd结构表示要监听的描述符。

int poll(struct pollfd *fds, nfds_t nfds, int timeout) struct pollfd{ short events; short revents;};

pollfd结构包括了events(要监听的事件)和revents(实际发生的事件)。而且也需要在函数返回后遍历pollfd来获取就绪的描述符。

相对于select,poll已不存在最大文件描述符限制。


五、epoll

epoll针对以上select和poll的主要缺点做出了改进,

主要包括三个主要函数,epoll_create, epoll_ctl, epoll_wait。

  • epoll_create:创建epoll句柄,会占用一个fd值,使用完成以后,要关闭。

int epoll_create(int size)

  • epoll_ctl:提前注册好要监听的事件类型,监听事件(文件可写,可读,挂断,错误)。不用每次都去轮询一遍注册的fd,而只是通过epoll_ctl把所有fd拷贝进内核一次,并为每一个fd指定一个回调函数。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

当就绪,会调用回调函数,把就绪的文件描述符和事件加入一个就绪链表,并拷贝到用户空间内存,应用程序不用亲自从内核拷贝。类似于在信号中注册所有的发送者和接收者,或者Task中注册所有任务的handler。

  • epoll_wait:监听epoll_ctl中注册的文件描述符和事件,在就绪链表中查看有没有就绪的fd,不用去遍历所有fd。
  • 相当于直接去遍历结果集合,而且百分百命中,不用每次都去重新查找所有的fd,用户索引文件的事件复杂度为O(1)
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

六、select & poll & epoll比较

  1. 每次调用select都需要把所有要监听的文件描述符拷贝到内核空间一次,fd很大时开销会很大。epoll会在epoll_ctl()中注册,只需要将所有的fd拷贝到内核事件表一次,不用再每次epoll_wait()时重复拷贝
  2. 每次select需要在内核中遍历所有监听的fd,直到设备就绪;epoll通过epoll_ctl注册回调函数,也需要不断调用epoll_wait轮询就绪链表,当fd或者事件就绪时,会调用回调函数,将就绪结果加入到就绪链表。
  3. select能监听的文件描述符数量有限,默认是1024;epoll能支持的fd数量是最大可以打开文件的数目,具体数目可以在/proc/sys/fs/file-max查看
  4. select, poll在函数返回后需要查看所有监听的fd,看哪些就绪,而epoll只返回就绪的描述符,所以应用程序只需要就绪fd的命中率是百分百。

表面上看epoll的性能最好,但是在连接数少并且链接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。

select效率低是一位每次都需要轮询,但效率低也是相对的,也可通过良好的设计改善


七、阻塞、非阻塞

这张图可以看出阻塞式I/O、非阻塞式I/O、I/O复用、信号驱动式I/O他们的第二阶段都相同,也就是都会阻塞到recvfrom调用上面就是图中“发起”的动作。异步式I/O两个阶段都要处理。这里我们重点对比阻塞式I/O(也就是我们常说的传统的BIO)和I/O复用之间的区别。

阻塞式I/O和I/O复用,两个阶段都阻塞,那区别在哪里呢?

虽然第一阶段都是阻塞,但是阻塞式I/O如果要接收更多的连接,就必须创建更多的线程。I/O复用模式下在第一个阶段大量的连接统统都可以过来直接注册到Selector复用器上面,同时只要单个或者少量的线程来循环处理这些连接事件就可以了,一旦达到“就绪”的条件,就可以立即执行真正的I/O操作。这就是I/O复用与传统的阻塞式I/O最大的不同。也正是I/O复用的精髓所在。

从应用进程的角度去理解始终是阻塞的,等待数据和将数据复制到用户进程这两个阶段都是阻塞的。这一点我们从应用程序是可以清楚的得知,比如我们调用一个以I/O复用为基础的NIO应用服务。调用端是一直阻塞等待返回结果的。

从内核的角度等待Selector上面的网络事件就绪,是阻塞的,如果没有任何一个网络事件就绪则一直等待直到有一个或者多个网络事件就绪。但是从内核的角度考虑,有一点是不阻塞的,就是复制数据,因为内核不用等待,当有就绪条件满足的时候,它直接复制,其余时间在处理别的就绪的条件。这也是大家一直说的非阻塞I/O。实际上是就是指的这个地方的非阻塞。


总结

我们通常说的NIO大多数场景下都是基于I/O复用技术的NIO,比如jdk中的NIO,当然Tomcat8以后的NIO也是指的基于I/O复用的NIO。注意,使用NIO != 高性能,当连接数<1000,并发程度不高或者局域网环境下NIO并没有显著的性能优势。如果放到线上环境,网络情况在有时候并不稳定的情况下,这种基于I/O复用技术的NIO的优势就是传统BIO不可同比的了。那么使用select的优势在于我们可以等到网络事件就绪,那么用少量的线程去轮询Selector上面注册的事件,不就绪的不处理,就绪的拿出来立即执行真正的I/O操作。这样我们就能够用极少量的线程去HOLD住大量的连接。

后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注下~

两个线程同时从服务器接收消息_一文看懂I/O多路复用技术(mysql线程池)相关推荐

  1. 两个线程同时从服务器接收消息_Linux高性能服务器处理框架

    本文为转载,文中所提到的知识点是每个Linux开发人员都需要考虑的问题.https://www.jianshu.com/p/db15ff4e8359 终于开始学习epoll了,虽然不明白的地方还是很多 ...

  2. weblogic多次连接后tcp服务堵塞_一文看懂 Web服务器、应用服务器、Web容器、反......

    导读:我们知道,不同肤色的人外貌差别很大,而双胞胎的辨识很难.有意思的是Web服务器/Web容器/Web应用程序服务器/反向代理有点像四胞胎,在网络上经常一起出现.本文将带读者对这四个相似概念如何区分 ...

  3. c#服务器后端_一文看懂Serverless:AWS阿里云腾讯云都在发力「无服务器架构」

    冠望 发自 凹非寺 量子位 报道 | 公众号 QbitAI 要说目前软件架构中热度十二分的话题,当属Serverless. 通常我们会将其翻译为"无服务器架构". 尽管成天被称为& ...

  4. rabbitmq实战:高效部署分布式消息队列_一文看懂消息队列中间件--AMQ及部署介绍...

    概述 最近有个小项目用到了AMQ来做消息队列,之前介绍的主要是rabbitmq,所以今天主要提一下AMQ,也简单介绍下两者的区别~ 消息队列中间件 消息队列中间件(简称消息中间件)是指利用高效可靠的消 ...

  5. controller 用 map 接收值_一文弄懂apply、map和applymap三种函数的区别

    CDA数据分析师 出品 在日常处理数据的过程中,会经常遇到这样的情况,对一个DataFrame进行逐行.逐列或者逐元素的操作,很多小伙伴也知道需要用到apply.map或者applymap,但是具体什 ...

  6. 判别两棵树是否相等 设计算法_一文看懂生成对抗网络 - GANs?(附:10种典型算法+13种应用)...

    生成对抗网络 – GANs 是最近2年很热门的一种无监督算法,他能生成出非常逼真的照片,图像甚至视频.我们手机里的照片处理软件中就会使用到它. 本文将详细介绍生成对抗网络 – GANs 的设计初衷.基 ...

  7. 连傻瓜都能看懂的基于代码注入的线程守护技术

    连傻瓜都能看懂的基于代码注入的线程守护技术 2010年08月31日 连傻瓜都能看懂的基于代码注入的线程守护技术 Author: 叶紫孤(CPP肥兔) (感谢冷风大哥提供技术支持) E-mail: ye ...

  8. 并发、并行、同步、异步、进程,线程、串行、并行?一文弄懂八大概念

    并发.并行.同步.异步.进程,线程.串行.并行?一文弄懂八大概念 参考博文:并发.并行.串行.同步.异步的区别? java多线程详解(并发,并行,同步) 文章目录 并发.并行.同步.异步.进程,线程. ...

  9. 海普天刷卡机刷卡的时候显示服务器连接失败,一文看懂智能消费机解决方案,解锁新知识...

    原标题:一文看懂智能消费机解决方案,解锁新知识 文章来源:海普天一卡通 消费机的市场发展也呈现出一个快速发展的趋势.据调查报告表明,未来消费机的发展将会以25%的增长趋势发展,智能消费机的发展使得它应 ...

最新文章

  1. Golang sync
  2. pci中断号分配_西门子S7-200 SMART中断及中断指令概述
  3. R语言进阶 | 变量赋值背后的机制与R语言内存优化
  4. swagger ui remove springboot paths
  5. java 中negate()_Java BigInteger negate()用法及代码示例
  6. STM32工作笔记0096---用sprintf分配内存
  7. struts2 ModelDriven 和 Preparable 拦截器
  8. UI设计,扁平化还是拟物化?
  9. 【云驻共创】当HarmonyOS走进课堂是种什么体验
  10. 【软件工具】Pycharm社区版安装ChatGPT!
  11. Cg学习记录003 之Varying参数
  12. 【测评】抗原乳化方法学评测:去离子水乳化、机械乳化法、PBS 缓冲液乳化..
  13. Springboot2 D3 SpringBoot开发实用篇 - 热部署 - 配置高级 - 测试
  14. 分分钟实现梦想 —— 两种快速打造App的方法
  15. 大数据未来会如何发展
  16. 如何通过IOCTL_ATA_PASS_THROUGH发送ATA命令并获取ASTS(ATA task file status)
  17. SNOWFLAKE(雪花ID)的实现
  18. TQ2440制作最小根文件系统
  19. 《C语言及程序设计》教学视频 18 链表中结点的插入和删除 示例代码
  20. linux wifi探针,Openwrt WIFI探针开发

热门文章

  1. 深入了解Kubernetes REST API的工作方式
  2. CSS3 3D transform变换
  3. Unable to load native-hadoop library解决思路
  4. 常用的JS小功能整理
  5. Magento怎么升级?
  6. Mybatis异常Invalid bound statement (not found): com.xxx.xxxMapper.selectxxxByxxx
  7. java输出变量_Java笔记1: 输入输出与变量常量
  8. 程序固化到优盘中_将Windows 8/10 系统装进优盘
  9. 利用计算机找出函数关系式,使用 CHOOSE 查找函数中类似于表的信息 - Excel公式函数运用大全...
  10. python从爬虫到数据分析项目_零基础学习Python web开发、Python爬虫、Python数据分析,从基础到项目实战!...