导航:首页 > 编程系统 > linuxselect阻塞模式

linuxselect阻塞模式

发布时间:2024-12-05 00:35:53

1. linux 高并发之IO多路复用select、poll和epoll的区别

文件描述符(fd)代表对文件操作的句柄,例如socket套接字。通常,对fd进行读写操作需要操作fd,如read(),但read()本身是BIO,即阻塞IO。当对fd调用read()时,如果没有数据输入到fd,read()会处于阻塞状态,直到有数据输入,read()才会返回。

如果有客户端连接到服务器并想要与服务器通信,那么服务器将对表示服务器的sd(socket也可作为fd)调用read()。此时,如果客户端有信息进入,read()将返回;否则,read()会一直阻塞。

如果有两个客户端连接到服务器并想要与服务器通信,怎么办?答案是开多线程,让另一个线程对第二个客户端调用read(),并阻塞到客户端有信息进入服务器为止。但这样会出现问题,实际应用中,客户端数量可能不止几个,可能有成千上万个客户端想要与服务器通信,那么也要开成千上万个线程?显然是不实际的。

因此,解决方案就是IO多路复用。IO多路复用一般有select()、poll()、epoll()方式,它们都是对连接到服务器的客户端socket进行监控。例如,现在有100个客户端socket,那么就监控这100个,如果这100个socket中有信息进入,则IO多路复用会返回;否则,就阻塞。即IO多路复用可以同时阻塞多个I/O操作,并且可以同时对多个读操作、多个写操作的I/O函数进行检测,直到有数据可读或可写(就是监听多个socket)。

由于阻塞I/O只能阻塞一个I/O操作,而I/O复用模型能够阻塞多个I/O操作,所以才叫做多路复用。

IO多路复用一般分为:select、poll、epoll三种方式。三个都属于系统调用。

2.1 select的大致过程如下:

用户进程调用select()监控用户指定的多个文件描述符,若没有一个文件描述符有数据返回,则阻塞;若有文件描述符有数据返回,则会对这个文件描述符调用read()进行读取数据。

2.2 poll的优缺点如下:

1. 相对于select,poll没有监听文件描述符的数目上限。

2. 由于poll监听文件描述符的方式都是轮询,与select一样,所以poll在高并发下的表现也不是特别好。

2.3 epoll的大致工作流程如下:

我们在调用epoll_create时,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个rdllist双向链表,用于存储准备就绪的文件描述符fd,当epoll_wait调用时,仅仅观察这个rdllist双向就绪链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。

所有添加到epoll中的fd都会与设备(如网卡)驱动程序建立回调关系,也就是说相应fd的监听事件发生时会调用这里的回调方法。这个回调方法在内核中叫做ep_poll_callback,它会把这样的fd放到上面的rdllist双向就绪链表中。

epoll特点:

2.3.1 操作epoll的接口

epoll_create (int size):创建(即返回)一个epfd句柄,参数size表明内核要监听的描述符数量。调用成功时返回一个epoll句柄描述符,失败时返回-1。

epoll_ctl (int epfd, int op, int fd, struct epoll_event *event):注册要监听的时间类型。

epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout):等待事件的就绪。

2.3.2 epoll的两种触发模式(LT和ET)

epoll有LT和ET两种触发模式,LT是默认的模式,ET是高速的模式。

ET模式在很大程度上降低了同一个epoll事件被重复触发的次数,因此ET模式效率比LT模式高。

2.3.3 对比select和poll的遗留缺点,epoll的解决方法

第一个:select和poll每次调用时都会反复在用户态和内核态中来回复制fd集合。

epoll的解决方案是:调用epoll_wait,相当于调用select、poll。而在epoll_ctl期间,把需要监听的fd一次性拷贝到内核,这样就避免了调用epoll_wait时把fd集合重复拷贝。

第二个:select和poll存在大量无效轮询。

epoll并不是像select一样去逐个轮询的监控fd的事件状态,而是事先就建立了fd与之对应的回调函数,当事件激活后主动回调callback函数,这也就避免了遍历事件列表的这个操作,所以epoll并不会像select和poll一样随着监控的fd变多而效率降低。

第三个:文件描述符上限的限制。

epoll没有最大监听文件描述符数目的限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

2. linux select函数解析以及事例

Linux系统中的I/O操作模式解析,主要涉及阻塞、非阻塞和I/O多路复用三种,其中前两者属于同步I/O,而多路复用是异步操作。同步I/O如阻塞I/O,如recv()函数,当数据未准备好时,进程会阻塞等待,直到数据接收完成。非阻塞模式虽然避免了等待,但可能导致CPU资源浪费。而I/O多路复用,如select函数,允许一个线程同时监测多个套接字,当其中任一有数据时,函数会立即返回,节省了线程和资源的开销。

select函数的用法包括清零fd_set(FD_ZERO)、添加待监测的fd(FD_SET)和检查fd状态(FD_ISSET)。其工作流程是:首先清零fd_set,然后将需要监测的文件描述符(fd)加入,调用select函数进行监测,最后根据FD_ISSET检查结果处理数据。在实际应用中,例如服务器端,可以利用select监控客户端连接,一旦有新连接,即可进行处理。

在使用示例中,服务器端通过select持续监听客户端连接,一旦接收到数据,即进行相应的逻辑处理。这简化了资源管理和提高程序效率。

3. 同步与异步,阻塞与非阻塞的区别,以及select,poll和epoll

异步的概念和同步相对。
(1)当一个同步调用发出后,调用者要一直等待返回消息(结果)通知后,才能进行后续的执行;

(2)当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。实际处理这个调用的部件在完成后,通过 状态、通知和回调 来通知调用者。

这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。使用哪一种通知机制,依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。

(A)阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务

(B)非阻塞调用是指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回

场景比喻:
举个例子,比如我去银行办理业务,可能会有两种方式:

在上面的场景中,如果:
a)如果选择排队(同步),且排队的时候什么都不干(线程被挂起,什么都干不了),是同步阻塞模型;
b)如果选择排队(同步),但是排队的同时做与办银行业务无关的事情,比如抽烟,(线程没有被挂起,还可以干一些其他的事),是同步非阻塞模型;
c)如果选择拿个小票,做在位置上等着叫号(通知),但是坐在位置上什么都不干(线程被挂起,什么都干不了),这是异步阻塞模型;
d)如果选择那个小票,坐在位置上等着叫号(通知),但是坐着的同时还打电话谈生意(线程没有被挂起,还可以干其他事情),这是异步非阻塞模型。

对这四种模型做一个总结:
1:同步阻塞模型,效率最低,即你专心排队,什么都不干。
2:异步阻塞,效率也非常低,即你拿着号等着被叫(通知),但是坐那什么都不干
3:同步非阻塞,效率其实也不高,因为涉及到线程的来回切换。即你在排队的同时打电话或者抽烟,但是你必须时不时得在队伍中挪动。程序需要在排队和打电话这两种动作之间来回切换,系统开销可想而知。
4:异步非阻塞,效率很高,你拿着小票在那坐着等叫号(通知)的同时,打电话谈你的生意。

linux下几个基本概念
1:用户控件和内核空间。 现代操作系统都是采用虚拟存储器,在32位操作系统下,它的寻址空间(虚拟存储空间)为4G(2的32次方)。为了保证用户进程补鞥呢直接操作内核,保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。对linux操作系统而言,将最高的1G字节空间分给了内核使用,称为内核空间,将较低的3G字节的空间划分为用户空间。

2:进程切换很耗资源 ,为了控制进程的执行,内核必须有能力挂起正在cpu上运行的进程,并恢复以前挂起的某个进程的执行,这种行为叫进程的切换。每次切换,要保存上一个的上下文环境等等,总之记住进程切换很耗资源。

3:文件描述符 :文件描述符在形式上是一个非负整数。实际上,他是一个索引,指向内核为每个进程所维护的该进程打开文件的记录表。当程序打开一个文件时,内核就会向进程返回一个非负整数的文件描述符。但是文件描述符一般在unix,linux系统中才讲。

缓存IO ,大多数系统的默认IO操作都是缓存IO,在linux的缓存IO机制中,操作系统会将IO的数据缓存在系统的页缓存(page cache)中,也就是说,数据会先被拷贝到操作系统内核的缓冲区,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。 缓存IO的缺点: 数据在传输过程中需要在应用程序和地址空间和内核进行多次数据拷贝操作,这种数据拷贝操作锁带来的cpu以及内存消耗是很大的。

LINUX的IO模型
网络IO的本质是socket的读取。socket在linux系统被抽象为流,故对网络IO的操作可以理解为对流的操作。

对于一次IO访问,比如以read操作为例, 数据会先被拷贝到操作系统内核的缓冲区,然后才会从内核缓冲区拷贝到进程的用户层,即应用程序的地址空间 。故当一个read操作发生时,其实是经历了两个阶段:
1:内核缓冲区的数据就位
2:数据从内核缓冲区拷贝到用户程序地址空间

那么具体到socket io的一次read操来说,这两步分别是:
1:等待网络上的数据分组到达,然后复制到内核缓冲区中
2:数据从内核缓冲区拷贝到用户程序的地址空间(缓冲区)

所以说 网络应用要处理的无非就两个问题:网络IO和数据计算 ,一般来说网络io带来的延迟影响比较大。

网络IO的模型大致有如下几种:

熟悉不? 我们常说的select,poll和epoll就是属于同步模型中多路复用IO的不同实现方法罢了。 下面分别对同步阻塞,同步不阻塞,同步io复用进行说明。

一:同步阻塞
它是最简单也最常用的网络IO模型。linux下默认的socket都是blocking的。

从图中可以看到,用户进程调用recvfrom这个系统调用后,就处于阻塞状态。然后kernel就开始了IO的第一个阶段:数据准备。等第一个阶段准备完成之后,kernel开始第二阶段,将数据从内核缓冲区拷贝到用户程序缓冲区(需要花费一定时间)。然后kernel返回结果(确切的说是recvfrom这个系统调用函数返回结果),用户进程才结束blocking,重新运行起来。
总结 同步阻塞模型下,用户程序在kernel执行io的两个阶段都被blocking住了 。但是优点也是因为这个,无延迟能及时返回数据,且程序模型简单。

二:同步非阻塞
同步非阻塞就是隔一会瞄一下的轮询方式。同步非阻塞模式其实是可以看做一小段一小段的同步阻塞模式。

三:IO多路复用
由于同步非阻塞方式需要不断的轮询,光轮询就占据了很大一部分过程,且消耗cpu资源。而这个用户进程可能不止对这个socket的read,可能还有对其他socket的read或者write操作,那人们就想到了一次轮询的时候,不光只查询询一个socket fd,而是在一次轮询下,查询多个任务的socket fd的完成状态,只要有任何一个任务完成,就去处理它。而且,轮询人不是进程的用户态,而是有人帮忙就好了。那么这就是所谓的 IO多路复用 。总所周知的linux下的select,poll和epoll就是这么干的。。。

selelct调用是内核级别的,selelct轮询相比较同步非阻塞模式下的轮询的区别为: 前者可以等待多个socket,能实现同时对多个IO端口的监听 ,当其中任何一个socket数据准备好了,就返回可读。 select或poll调用之后,会阻塞进程 ,与blocking IO 阻塞不用在于,此时的select不是等到所有socket数据达到再处理,而是某个socket数据就会返回给用户进程来处理。
其实select这种相比较同步non-blocking的效果在单个任务的情况下可能还更差一些 ,因为这里调用了select和recvfrom两个system call,而non-blocking只调用了一个recvfrom,但是 用select的优势在于它可以同时处理多个socket fd

在io复用模型下,对于每一个socket,一般都设置成non-blocking,但是其实 整个用户进程是一直被block的 ,只不过用户process不是被socket IO给block住,而是被select这个函数block住的。

与多进程多线程技术相比,IO多路复用的最大优势是系统开销小。

一:select
select函数监视多个socket fs,直到有描述符就绪或者超时,函数返回。当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。select的基本流程为:

二:poll
poll本质上跟select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd的状态,如果某个fd的状态为就绪,则将此fd加入到等待队列中并继续遍历。如果遍历完所有的fd后发现没有就绪的,则挂起当前进程,直到设备就绪或者主动超时。被唤醒后它又要再次遍历fd。
特点:
1:poll没有最大连接数限制,因为它是用基于链表来存储的,跟selelct直接监听fd不一样。
2:同样的大量的fd的数组被整体复制与用户态和内核地址空间之间。
3:poll还有一个特点是水平触发:如果报告了fd后没有被处理,则下次poll时还会再次报告该fd。
4:跟select一样,在poll返回后,还是需要通过遍历fdset来获取已经就绪的socket。当fd很多时,效率会线性下降。

三:epoll

epoll支持水平触发和边缘触发,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次。还有一个特点是,epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。

没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口)。

效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。

内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。

聊聊同步、异步、阻塞与非阻塞
聊聊Linux 五种IO模型
聊聊IO多路复用之select、poll、epoll详解

阅读全文

与linuxselect阻塞模式相关的资料

热点内容
怎么编程apk 浏览:506
ccs环境下的仿真器配置文件 浏览:123
门户网站配色分析 浏览:387
如何读取谷歌缓存文件 浏览:243
网络罗汉什么意思 浏览:508
还助学贷款用什么网站 浏览:505
广州哪里学少儿编程比较好 浏览:304
java关闭class 浏览:165
除了迅雷还有哪些好用的app 浏览:155
犀牛建模新手教程视频教程下载 浏览:345
相机磁吸数据线哪里可以买到 浏览:265
自定义文件名 浏览:242
智能小车蓝牙app 浏览:963
u盘文件过了一会自动消除 浏览:59
下载微信50版本到手机 浏览:529
js判断是否为json数组 浏览:419
领克app启动引擎后是什么意思 浏览:936
iphone跑马灯可以退货吗 浏览:770
西门子plc模拟量输入怎么编程 浏览:281
狂战异界升级 浏览:380

友情链接