流?I/O操作? 阻塞?
(1)流
▪ 可以進⾏I/O操作的內核對象
▪ ⽂件、管道、套接字……
▪ 流的⼊⼝:⽂件描述符(fd)
(2)I/O操作
所有對流的讀寫操作,我們都可 以稱之為IO操作。
(3)阻塞
阻塞等待 不占⽤CPU寶貴的時間⽚
⾮阻塞忙輪詢 占⽤CPU,系統資源
在處理意⻅數據的接收場景時, 我們建議優先選擇阻塞等待的⽅ 式, 不浪費性能資源
(4)阻塞等待缺點:
不能夠很好的處理 多個(I/O)請求的問題
同⼀個阻塞,同⼀時刻只能處理⼀個流的阻塞監聽
(5)多路IO復⽤
既能夠阻塞等待,不浪費資源
也能夠同⼀時刻監聽多個IO請求的狀態
解決阻塞死等待的缺點(如何解決⼤量IO請求讀寫的問題)
⽅法⼀ : 阻塞等待+多進程/多線程
需要開辟線程浪費資源
⽅法⼆:⾮阻塞+忙輪詢
while true { for i in 流[] { if i has 數據 { 讀 或者 其他處理 } } }
CPU在⼤量的做判斷,while和for
cpu的利⽤率不⾼
方法三:多路IO復⽤機制 select(與平台⽆關)
監聽的IO數量有限,默認是1024個
不會精准的告訴開發者,哪些IO是可讀可寫的,需要遍歷
while true { select(流[]); //阻塞 //有消息抵達 for i in 流[] { if i has 數據 { 讀 或者 其他處理 } } }
方法四:多路IO復⽤機制 epoll(Linux)
通過 /proc/sys/fd/file-max查看)
while true { 可處理的流[] = epoll_wait(epoll_fd); //阻塞 //有消息抵達,全部放在 “可處理的流[]”中 for i in 可處理的流[] { 讀 或者 其他處理 } }
epoll 的API
(1) 創建EPOLL
int epoll_create(int size);
(2) 控制EPOLL
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
(3) 等待EPOLL
int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout);
(4) 使⽤epoll編程主流程⻣架
觸發模式
⽔平觸發:
⽔平觸發的主要特點是,如果⽤戶在監聽epoll事件,當內核有事件的時候,會拷⻉給⽤戶態事 件,但是如果⽤戶只處理了⼀次,那么剩下沒有處理的會在下⼀次epoll_wait再次返回該事 件。
默認就是⽔平觸發模式
邊緣觸發:
邊緣觸發,相對跟⽔平觸發相反,當內核有事件到達, 只會通知⽤戶⼀次,⾄於⽤戶處理還是不處理, 以后將不會再通知。這樣減少了拷⻉過程,增加了性能,但是相對來說,如果⽤戶⻢⻁忘記處理,將會產 ⽣事件丟的情況。
在給事件進⾏綁定的時候,通過EPOLLET來設置