每日一句
人的痛苦會把自己折磨到多深呢?
每日一句
You cannot swim for new horizons until you have courage to lose sight of the shore.
除非有勇氣離開岸邊,否則你永遠游不到彼岸,
概念
IO 是主存和外部設備(硬碟、終端和網路等)拷貝資料的程序,IO是作業系統的底層功能實作,底層通過I/O指令進行完成,
以下是5種類Unix下可用的I/O模型
1. 阻塞式I/O:Blocking IO
2. 非阻塞式I/O:nonblocking IO
3. I/O 復用(Select,poll epoll):IO multiplexing
4. 信號驅動式I/O(SIGIO):signal driven IO
5. 異步 I/O(posix 的 aio 系列函式):asynchromous IO
Blocking IO
在 Linux 中,默認情況下所有的 socket 都是 Blocking,一個典型的讀操作流程大概是這樣:
1. 通常涉及等待資料從網路到達,當所有等待資料到達時,它被復制到內核中的某個緩沖區
2. 把資料從內核緩沖區復制到應用程式緩沖區
當用戶行程呼叫了 recvfrom 這個系統呼叫, kernel 就開始了 IO 的第一個階段:準備資料,對于 network IO 來說,很多時候資料在一開始還沒有到達(比如,還沒有收到一個完整的 UDP 包),這個時候 kernel 就要等待足夠的資料到來,而在用戶行程這邊,整個行程會被阻塞,當 kernel 一直等到資料準備好了,它就會將資料從kernel 中拷貝到用戶記憶體,然后kernel回傳結果,用戶行程才解除 block 的狀態,重新運行起來,
所以,Blocking IO 的特點就是在IO執行的兩個階段都被 block了
非阻塞式I/O
Linux 下,可以用過設定 socket 使其變為 non-blocking,當對一個 non-blocking socket 執行操作時,流程如下:
從圖中可以看出,當用戶行程發出read操作時,如果kernel中的資料還沒有準備好,那么它并不會block用戶行程,而是立刻回傳一個error, 從用戶行程角度講 ,它發起一個read操作后,并不需要等待,而是馬上就得到了一個結果,用戶行程判斷結果是一個error時,它就知道資料還沒有準備好,于是它可以再次 發送read操作,一旦kernel中的資料準備好了,并且又再次收到了用戶行程的system call,那么它馬上就將資料拷貝到了用戶記憶體,然后回傳,
所以,用戶行程第一個階段不是阻塞的,需要不斷的主動詢問kernel資料好了沒有;第二個階段依然總是阻塞的,
IO 多路復用(NIO)
select、epoll 的好處就在于單個 process 就可以同時處理多個網路鏈接的 IO,
IO 復用和同步阻塞本質一樣,不過利用了新的 Select 系統呼叫,由內核來負責本來是請求行程該做的輪訓操作,看似不非阻塞IO還多了哥系統呼叫開銷,不過因為支持多路IO才算提高了效率
也就是一個可以監聽多個,
它的基本原理就是 select、epoll 這個 function會不斷的輪詢所負責的所有 socket,當某個 socket 有資料到達了,就通知用戶行程,它的流程如下圖:
當用戶執行緒呼叫select,那么整個行程會被阻塞,而同時,kernel會監視所有select負責的 socket =,當任何一個 socket 中的資料準備好了,select 就會回傳,這個時候用戶行程會呼叫 read 操作,將資料 kernel 拷貝到用戶行程,
首先開啟套接字的信號驅動式IO功能,并且通過sigaction(信號處理程式) 系統呼叫安裝一個信號處理函式 ,該函式呼叫將立即回傳,當前行程沒有被阻塞 ,繼續作業;當資料報準備好的時候,內核為該行程產生SIGIO 的信號,隨后既可以在信號處理函式中呼叫recvfrom 讀取資料報,并且通知主回圈資料已經準備好等待處理;也可以直接通知主回圈讓它讀取資料報;(其實就是一個待讀取的通知和待處理的通知),基本不會用到,
異步IO(AIO)
多執行緒和多行程的模型雖然解決了并發的問題,但是系統不能無限的增加執行緒,由于系統的切換執行緒的開銷恒大,所以,一旦執行緒數量過多,CPU的時間就花在執行緒的切換上,正真運行代碼的時間就會減少,結果導致性能嚴重下降
由于我們要解決的問題是CPU高速執行能力和IO設備的龜速嚴重不匹配,多執行緒和多行程只是解決這一個問題的一種方法,
另一種解決IO問題的方法是異步IO,當代碼需要執行一個耗時的IO操作時,他只發出IO指令,并不等待IO結果然后就去執行其他代碼,一段時間后,當IO回傳結果是,在通知CPU進行處理我們呼叫aio_read函式,給內核傳遞描述符,緩沖區指標,緩沖區大小,和檔案偏移量,并且告訴內核當整個操作完成時如何通知我們,該函式呼叫后,立即回傳,不會被阻塞
另一方面:從kernel的角度,當他收到一個aio_read之后,首先它立即回傳,所以不會對用戶行程產生block,然后kernel會等待資料準備完成,然后將資料拷貝到用戶記憶體(copy由內核完成),當著一切完成后,kernel會給用戶行程發送一個singal或者執行下一個基于執行緒回呼函式來完成此次IO處理程序,告訴他read操作完成
美文佳句
歲月應是靜好,近來,心神總是不寧,想必是被塵世間的傭訓所困,
我想,要是遠方的祥夫先生來到我這“梅知堂”,兩人清茶一杯,盤腿而坐,或看他畫梅,紙上的梅花仿佛兀自開在飛雪里,如是,那該是一幅怎樣的墨梅圖?
昨晚,夢里看到那個戴著小黑圓眼鏡的祥夫背著黃色的大包正往江南趕路,是又到了梅花開的日子了嗎?
面試題
SpringMVC作業原理?
1. 客戶端發送請求到前端控制器 DispatcherServlet
2. DispatcherServlet 收到請求后,呼叫 HandlerMapping 處理器映射器,請求獲取 handler
3. 處理器映射器根據 url 找到具體的處理器,生成處理器物件以及處理器攔截器(如果有則生成)一并回傳給 DispatcherServlet
4. DispatcherServlet 呼叫 HandlerAdapter 處理器配接器
5. HandlerAdapter 經過配接器呼叫 具體處理器(Handler,也叫后端控制器)
6. Handler 執行完成回傳 ModelAndView
7. HandlerAdaper 將 Handler 執行結果 ModelAndView 回傳給 DispatcherServlet
8. DispatcherServlet 將 ModelAndView 傳給 ViewResolver 視圖決議器 進行決議
9. ViewResolver 決議后回傳具體 View
10. DispatcherServlet 對 view 進行 渲染視圖(即將模型資料填充至視圖中)
11. DispatcherServlet 回應用戶
ArrayList 、LinkedList和Vector的區別?
| ArrayList | LinkedList | Vector | |
| 執行緒是否安全 | 不保證 | 不保證 | 保證執行緒安全,但是底層大量使用了synchronized關鍵字,效率不是很高 |
| 底層資料結構 | 陣列,查詢效率高,多用于查詢較多的場合 | LinkedList 底層是雙向鏈表,插入和洗掉非常方便,適用于插入較多的場合 | 陣列,查詢效率高,多用于查詢較多的場合 |
| 默認大小與擴容 | JDK 1.7 之前默認大小是 10 JDK 1.7 之后是0 每次按照1.5倍擴容 | 底層是鏈表結構,是不連續的存盤空間,沒有默認大小的說法 | Vector擴容是2倍 |
@RestController 和 @Controller 有什么區別?
@RestController 注解,在 @Controller 基礎上,增加了 @ResponseBody 注解,更加適合目前前后端分離的架構下,提供 Restful API ,回傳例如 JSON 資料格式,當然,回傳什么樣的資料格式,根據客戶端的 "ACCEPT" 請求頭來決定,
你好,我是yltrcc,日常分享技術點滴,歡迎關注我:ylcoder
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/458219.html
標籤:其他
