一次读懂 Select、Poll、Epoll IO复用技术

https://baijiahao.baidu.com/s?id=1611547498841608701&wfr=spider&for=pc

我们之前采用的多进程方式实现的服务器端,一次创建多个工作子进程来给客户端提供服务。其实这种方式是存在问题的。

可以打个比方:如果我们先前创建的几个进程承载不了目前快速发展的业务的话,是不是还得增加进程数?我们都知道系统创建进程是需要消耗大量资源的,所以这样就会导致系统资源不足的情况。

那么有没有一种方式可以让一个进程同时为多个客户端端提供服务?

接下来要讲的IO复用技术就是对于上述问题的最好解答。

对于IO复用,我们可以通过一个例子来很好的理解它。(例子来自于《TCP/IP网络编程》)

某教室有10名学生和1名老师,这些学生上课会不停的提问,所以一个老师处理不了这么多的问题。那么学校为每个学生都配一名老师,

也就是这个教室目前有10名老师。此后,只要有新的转校生,那么就会为这个学生专门分配一个老师,因为转校生也喜欢提问题。如果把以上例子中的学生比作客户端,那么老师就是负责进行数据交换的服务端。则该例子可以比作是多进程的方式。

后来有一天,来了一位具有超能力的老师,这位老师回答问题非常迅速,并且可以应对所有的问题。而这位老师采用的方式是学生提问前必须先举手,确认举手学生后在回答问题。则现在的情况就是IO复用。

目前的常用的IO复用模型有三种:select,poll,epoll。


select模型:

说的通俗一点就是各个客户端连接的文件描述符fd 也就是套接字,都被放到了一个集合中,调用select函数之后会一直监视这些文件描述符中有哪些可读,如果有可读的描述符那么我们的工作进程就去读取资源。PHP 中有内置的函数来完成 select 系统调用。

函数原型:

int socket_select (array &$read ,array &$write ,array &$except ,int $tv_sec [,int $tv_usec= 0 ])

作用说明:用于确定一个或多个套接字的状态,对每一个套接字,调用者可查询它的可读性、可写性及错误状态信息

参数说明:

read: 指向一组等待可读性检查的套接字

write: 指向一组等待可写性检查的套接字

except: 指向一组等待错误检查的套接字

tv_sec: 用来设置 select() 的等待时间,秒

tv_usec: 用来设置 select() 的等待时间,微妙

这里注意一下,如果 tv_sec 设置为0,则 socket_select 立即返回,也就是非阻塞的。如果 tv_sec 设置为 null ,则 socket_select 将一直阻塞到有套接字满足条件。


poll模型:

poll 和 select 的实现非常类似,本质上的区别就是存放 fd 集合的数据结构不一样。select 在一个进程内可以维持最多 1024 个连接,poll 在此基础上做了加强,可以维持任意数量的连接。

但 select 和 poll 方式有一个很大的问题就是,我们不难看出来 select 是通过轮训的方式来查找是否可读或者可写,打个比方,如果同时有100万个连接都没有断开,而只有一个客户端发送了数据,所以这里它还是需要循环这么多次,造成资源浪费。

所以后来出现了 epoll系统调用。


epoll模型:

epoll 是 select 和 poll 的增强版,epoll 同 poll 一样,文件描述符数量无限制。

epoll是基于内核的反射机制,在有活跃的 socket 时,系统会调用我们提前设置的回调函数。而 poll 和 select 都是遍历。

但是也并不是所有情况下 epoll 都比 select/poll 好,比如在如下场景:

在大多数客户端都很活跃的情况下,系统会把所有的回调函数都唤醒,所以会导致负载较高。既然要处理这么多的连接,那倒不如 select 遍历简单有效。


应用场景

很容易产生一种错觉认为只要用 epoll 就可以了,select 和 poll 都已经过时了,其实它们都有各自的使用场景。

  1. select 应用场景
    select 的 timeout 参数精度为 1ns,而 poll 和 epoll 为 1ms,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。
    select 可移植性更好,几乎被所有主流平台所支持。

  2. poll 应用场景
    poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。

  3. epoll 应用场景
    3.1 只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。
    3.2 需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。
    3.3 需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值