Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IO模型,同步异步,阻塞非阻塞, Select, Poll, Epoll #29

Open
meton-robean opened this issue Dec 19, 2019 · 5 comments
Open
Labels

Comments

@meton-robean
Copy link
Owner

meton-robean commented Dec 19, 2019

几张图比较清楚说明关系
参考https://cloud.tencent.com/developer/article/1005481

一个关于epoll的总结挺好:
https://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html

@meton-robean
Copy link
Owner Author

meton-robean commented Dec 19, 2019

同步IO之 Blocking IO

image

@meton-robean
Copy link
Owner Author

meton-robean commented Dec 19, 2019

同步IO之 NonBlocking IO

image

Repository owner locked and limited conversation to collaborators Dec 19, 2019
@meton-robean
Copy link
Owner Author

同步IO之 IO多路复用

image
IO多路复用,就是我们熟知的select、poll、epoll模型。从图上可见,在IO多路复用的时候,process在两个处理阶段都是block住等待的。初看好像IO多路复用没什么用,其实select、poll、epoll的优势在于可以以较少的代价来同时监听处理多个IO。

  • 多路复用:
    与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

  • 关于selcet, poll的缺点:

  1. poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。

  2. 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

2.同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

3.select支持的文件描述符数量太小了,默认是1024

  • epoll的改进:
    epoll提供了三个函数,epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生。
  1. 对于前面第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。

  2. 对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用schedule_timeout()实现睡一会,判断一会的效果,和select实现中的第7步是类似的)。

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

总结:
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。

(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。
摘自https://www.cnblogs.com/anker/p/3265058.html

@meton-robean meton-robean changed the title IO模型,Select, Poll, Epoll IO模型,同步异步,阻塞非阻塞, Select, Poll, Epoll Dec 22, 2019
@meton-robean
Copy link
Owner Author

异步IO:

image
异步IO要求process在recvfrom操作的两个处理阶段上都不能等待,也就是process调用recvfrom后立刻返回,kernel自行去准备好数据并将数据从kernel的buffer中copy到process的buffer在通知process读操作完成了,然后process在去处理。遗憾的是,linux的网络IO中是不存在异步IO的,linux的网络IO处理的第二阶段总是阻塞等待数据copy完成的。真正意义上的网络异步IO是Windows下的IOCP(IO完成端口)模型。

@meton-robean
Copy link
Owner Author

总的比较:

image

@meton-robean meton-robean added C++/C c++ Linux kernel 操作系统内核 labels Mar 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

1 participant