通俗易懂说多路复用(1)select


多路复用系列:
通俗易懂说多路复用(1)select
https://blog.csdn.net/lqy971966/article/details/89173936
通俗易懂说多路复用(2)epoll
https://blog.csdn.net/lqy971966/article/details/89217648
通俗易懂说多路复用(3)eventfd 事件通知
https://blog.csdn.net/lqy971966/article/details/104751751
通俗易懂说多路复用(4)fcntl
https://blog.csdn.net/lqy971966/article/details/105390106

1. 什么是多路复用?

1.1 复用的概念

复用技术 multiplexing 并不是新技术而是一种设计思想,在通信和硬件设计中存在频分复用、时分复用、波分复用、码分复用等,在日常生活中复用的场景也非常多,因此不要被专业术语所迷惑。

从本质上来说,复用就是为了解决有限资源和过多使用者的不平衡问题,从而实现最大的利用率,处理更多的问题。

1.2 多路复用定义

多路复用就是通过一种机制,可以监听多个描述符,一旦某个描述符就绪(可以读/写),就通过某种方法通知相应程序进行相应操作。
(其中,**文件描述符(fd)**是一个整数,起到一个索引的作用。进程通过fd找到fd指向的文件指针,从而对文件进行操作。)

1.3 通俗易懂的举例说明:多路复用

假设你在家一边玩游戏过程中,水壶正在烧水,洗衣机同时在洗衣服。不久,游戏过程中,水壶响了,你就去倒水;洗衣机洗好了,你就去晾衣服。你通过听它们的响声“滴滴滴”来判断事情有没有完成,然后进行下一步操作。
在这里水壶烧水,洗衣机洗衣服就分别是一个文件描述符;
他们任务完成了,发出“滴滴滴”的响声,就是描述符就绪了,通知你可以进行操作了。
多路复用在这里就是有许多家务在进行着,其中你对多项任务进行监听,通过某种方法来判断它们有没有完成,从而进行下一步操作。

1.4 多路复用种类

多路复用的方法有:select,poll,epoll

2. 什么是select?

2.1 select背景:原始处理方法

1. 原始处理方式:
在select,poll,epoll出现之前,最初处理多路复用的方法是:通过非阻塞忙轮询I/O的方式处理多个描述符(流)
2. 特点: 不停的从头到尾地轮询所有描述符/流
3. 缺点: 如果所有的流都没有数据,cpu空转,浪费cpu资源
4. 伪代码:

while true{ //一直轮询多有流
	if i in streams[] { //如果有描述符就绪,就进行处理
		read until unavailable
	}
}

2.2 select定义

select 是 2000年左右出现的,对外的接口定义:

/* According to POSIX.1-2001 */
#include <sys/select.h>

/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
		fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

参考:
https://blog.csdn.net/chinesehuazhou2/article/details/108353712
1. 定义:
为了解决原始处理方式的cpu空转浪费资源问题,引入了一个代理叫做select。select 通过同时监听多个描述符/流,在空闲的时候,把当前处理线程阻塞掉,当有一个或多个描述符/流就绪的时候,就从阻塞状态中醒来进行处理。

2.3 select优缺点及复杂度

2.3.1. 优点:

  1. select作为先驱对IO复用有巨大的推动,并且指明了后续的优化方向
  2. 只需要轮询一遍流,就知道有描述符就绪;

2.3.2. 缺点:

  1. 可协调fd数量和数值都不超过1024 无法实现高并发
  2. 使用O(n)复杂度遍历fd数组查看fd的可读写性 效率低
  3. 涉及大量kernel和用户态拷贝 消耗大
  4. 每次完成监控需要再次重新传入并且分事件传入 操作冗余

2.3.3. 复杂度:*O(n)

2.4 select伪代码

1. 伪代码:

int fds[] =  存放需要监听的socket

while(1){
	/*如果fds中的所有socket都没有数据,select会阻塞,
	直到有一个socket接收到数据,select返回,唤醒进程。*/
	int n = select(..., fds, ...) 
	
	/* 遍历fds,通过FD_ISSET判断具体哪个socket收到数据,然后做出处理 */
	for(int i=0; i < fds.count; i++){ 
		if(FD_ISSET(fds[i], ...)){
			//fds[i]的数据处理
		}
	}
}

3. 参考:

我读过的最好的epoll讲解 -知乎
https://www.zhihu.com/question/20122137/answer/14049112
https://zhuanlan.zhihu.com/p/64138532
https://zhuanlan.zhihu.com/p/63179839

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值