基本概念:
•流:文件、套接字、管道…
•I/O操作:read/write
•阻塞I/O:一个线程只能处理一个流的I/O事件(多线程pthread_create效率低)
epoll: event poll
•不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们。此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))
简单示例:
•epoll_create 创建一个epoll对象,一般epollfd = epoll_create()
•epoll_ctl (epoll_add/epoll_del的合体),往epoll对象中增加/删除某一个流的某一个事件
•epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);//注册缓冲区非空事件,即有数据流入
•epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT);//注册缓冲区非满事件,即流可以被写入
•epoll_wait(epollfd,…)等待直到注册的事件发生
非阻塞忙轮询的I/O方式:
#不停的把所有流从头到尾问一遍,又从头开始。这样就可以处理多个流了 |
---|
如果所有的流都没有数据,那么只会白白浪费CPU
whiletrue{
fori in stream[]; {
ifi has data:
read until unavailable
}
}
无差别轮询的I/O方式:
#在空闲的时候,会把当前线程阻塞掉 #当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流。O(n)的无差别轮询复杂度 whiletrue { select(streams[]) fori in streams[] { ifi has data read until unavailable } } |
---|
有意义轮询的I/O方式:
#不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们。此时我们对这些流的操作都是有意义的。复杂度降低到了O(1) whiletrue { active_stream[] = epoll_wait(epollfd) fori in active_stream[] { read or write till } } |
---|