預備知識
一切從任務(行程或執行緒)狀態變化說起
計算機由單個程式到多個程式運行及整批系統到分時系統,這一切都是為了更有效率地使用計算機,現在我們討論在單核情況下的計算機是如何運作的,每個任務的運行都被分配一個時間片段,時間到就會發起系統中斷告知系統,讓CPU可以去執行其他任務,由於每個時間片段都時間都非常短,所以我們會覺得好像所有的任務都是同時運作的,但其實不然,這些任務是一個接著一個按照順序被執行的,我們把這個現象稱之為並行(中國用語:並發)。如果說在時間片段期間我們發起會阻塞當前任務的系統調用,那麼當前任務所有相關資訊都會被保存,然後被放入等待佇列當中,該任務狀態為阻塞,排班程式會為我們分派其他任務並且配置CPU給其使用,而這個被作業系統阻塞的任務其發起的系統調用會經由DMA來進行處理資料的交換,等待完成搬移資料會發出I/O中斷告知作業系統,此時作業系統將會從該任務暫停的地方開始繼續執行。
以下是任務狀態流程圖:
並行與平行
並行(Concurrency),中國用語並發
任務在不同時間點被分配CPU來執行處理,也就是說在同一個時間點,任務不可能同時執行的。
平行(Parallelism),中國用語並行
每一個任務都可以分別被分配至不同的CPU來執行處理,也就是說在同一個時間點下,被分配CPU的任務可以同時執行。平行是基於多核處理器才能實現的。
用一張圖說明並行與平行:
I/O與CPU傾向任務
I/O傾向任務(I/O-bound )
CPU執行時間短,I/O執行時間長。(優先權重較CPU傾向任務高)
CPU傾向任務(CPU-bound )
CPU執行時間長,I/O執行時間短。
阻塞、非阻塞
調用阻塞I/O
作業系統層面
任務調用阻塞I/O後,系統不會返回結果,會將當前任務相關資訊保存,並且將CPU使用權歸還,讓CPU執行其他任務,而該任務進入等待佇列,此時狀態為阻塞態,並且等待處理I/O的控制器處理完資料發出中斷告知系統,系統才會返回結果。
程式層面
因為此刻任務為阻塞態,所以什麼事都不做,就只有等待,接收到系統返回的結果後,此任務才能繼續往下執行。
調用非阻塞I/O
作業系統層面
任務調用非阻塞I/O後,系統會立即返回一結果或一個錯誤,不會將當前任務阻塞,此任務仍然被CPU執行著,佔用著CPU,CPU會一直處理狀態判斷,接收來自應用層面不斷輪詢的非阻塞調用。
程式層面
此任務透過不斷輪詢的方式,向系統檢查是否有結果,而系統會不斷返回結果給該任務。
阻塞與非阻塞的差異
- 阻塞I/O不能進行並行操作的,很重要在這裡我指的是該任務本身的程式,而不是利用作業系統的多行程/多執行緒來實現並行操作,對於非阻塞I/O來講,可以實現程式本身的並行操作,這就是為什麼非阻塞I/O執行效率比較高的一個原因。
- 非阻塞I/O調用後會立即返回結果或一個錯誤,而阻塞I/O調用後則不會立即返回
- 調用非阻塞I/O的任務,仍然佔據著CPU,所以不會被阻塞,而調用阻塞I/O的任務會釋出CPU的使用權,進入阻塞狀態
同步、異步
什麼是同步?
以例子來說,現在在腳本中有兩個函數A與B,其中在A中我們調用B函數,A函數必須等到B函數執行完,返回結果後,A函數才能繼續執行,這個期間A函數必須等待。同步有個特色那就是等待,也就是說他是順序執行一個接著一個。
什麼是異步?
當一個異步方法調用發出後,會立即返回一個錯誤或結果,讓其回到應用本身可以繼續往下執行,如果說該應用不只發出一個異步調用,彼此之間不需要等待誰先完成才能執行下一個,它們是平行操作的,執行結果誰先返回不一定,這就是異步的特色。
以下我們來看一下這段程式碼的執行結果:
可以發現上圖的異步執行結果,我們對其發出了兩個異步調用,可以看到它們的返回順序不一致,這就是異步的特色,讓其可以平行處理,不需要彼此等待。
參考來源
- 《深入淺出node.js》。朴靈。北京。人民郵電出版社。
- 【操作系统】詳解阻塞、非阻塞、同步、異步
- 行程管理『行程與執行緒概念