为了更清楚的理解 Epoll 为什么这么快,我们就得先了解一下,不使用 Epoll 为什么慢。
在很久很久以前,当多个客户端请求服务端时,直接调用 kernel 提供的 read 函数,就可以处理客户端的请求。但是 read 函数是阻塞的,如果 read 函数阻塞在了 fd8 连接上,是不能处理 fd9 的请求的
image.png
这时候能想到的解决办法,就是使用多线程处理客户端的请求。多线程默认会占用 1m 的内存空间,加之多线程导致的上下文切换问题,成本很高。这该如何是好?
得益于 kernel 的演进,在建立 socket 的时候,可以指定是非阻塞的。这样调用 read 方法时,直接返回结果,进程不会阻塞。我们需要不断的轮询 fd8 fd9 有没有数据到来。问题在于轮询是发生在用户空间的,如果有 1000 个fd,代表用户进程轮询调用 1000 次 kernel,成本有点高,如果轮询 fd 的操作能直接交给 kernel 来处理就好了。
image.png
kernel 提供了一个 select 函数,我们可以把 1000 个 fd 一次性提交给 kernel,kernel 会对这 1000 个 fd 进行轮询,返回有数据的 fd,然后就可以调用 read 函数,对这些有数据的 fd 进行处理。这样虽然解决了问题,但是每次都需要把这 1000 个 fd 从用户态拷贝到内核态,这每次拷贝 fd 的开销能不能解决呢
image.png
这时候 epoll 就出现了,它的原理就是开辟一块新的内存空间,这块空间是用户态和内核态共享的。这样所有的 fd 都会放到这块共享空间,避免了用户态和内核态数据拷来拷去导致的开销
image.png
网友评论