Draymonders / Code-Life

The marathon continues though.
27 stars 3 forks source link

select / poll / epoll #42

Open Draymonders opened 4 years ago

Draymonders commented 4 years ago

所述三个均是处理网络请求的

https://www.bilibili.com/video/BV1qJ411w7du

Draymonders commented 4 years ago

正常情况我们会用一个线程去处理一个请求,但是在访问量高的情况下,上下文切换代价较高。

能不能用单线程就处理很多的请求呢,答案是可以的。

问题是单线程请求数据会丢失么?(即一个请求正在处理,第二个请求发过来)答案是不会的。因为请求一开始并不到达CPU,而是通过硬件->内存->CPU, 所以请求数据可以保存在内存。因而不会丢失。等处理完一个请求后,可以接着处理第二个请求。

Draymonders commented 4 years ago

select

缺点

Draymonders commented 4 years ago

poll

poll采用了如下的pollfd的结构体,放弃了bitmap

struct pollfd {
    int fd;
    short events;
    short revents;
};

这里处理仍和select相同,fd请求的句柄fdevents存想监听的事件IN OUT, revents是反馈。 具体就是 内核态拷贝pollfds数组,然后监听请求,发现有新的数据到来,便修改revents,然后返回给用户态

缺点

Draymonders commented 4 years ago

epoll

不需要轮询,时间复杂度为O(K)(K为同时来的请求数) (底层使用红黑树) epoll_create 创建一个白板 存放fd_events epoll_ctl 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上 epoll_wait 通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符

Draymonders commented 4 years ago

两种触发模式

LT:水平触发

当 epoll_wait() 检测到描述符事件到达时,将此事件通知进程,进程可以不立即处理该事件,下次调用 epoll_wait() 会再次通知进程。是默认的一种模式,并且同时支持 Blocking 和 No-Blocking。

ET:边缘触发

和 LT 模式不同的是,通知之后进程必须立即处理事件。 下次再调用 epoll_wait() 时不会再得到事件到达的通知。很大程度上减少了 epoll 事件被重复触发的次数, 因此效率要比 LT 模式高。只支持 No-Blocking,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

Draymonders commented 4 years ago

select 和 poll 均为阻塞(即有请求了,才会返回值) epoll为非阻塞