以前一直沒有分清楚 asynchronous 和 non-blocking 的差異, 寫久了以後才明白兩者是不同層次的東西。
- asynchronous programming: 程式不是一條線走到底, 可能目前做到一個段落停下來, 「過一會兒」再繼續執行
- non-blocking IO: 呼叫讀寫函式時, 不會等到完成才返回
通常要讀寫外部資料時 (一般檔案、網路、pipe 等) , 無法確定返回的時間, 這樣會阻擋程式的運作, 所以希望這個讀取 (或寫入) 不要等完成後才返回 (即「非同步」)。
若不希望此次呼叫有不確定時間的擔擱, 有兩種可能的作法:
- 開新 thread 或用既有的 thread 進行讀寫。總之, 停是停別人家的 thread, 和本 thread 無關
- 設定 file descriptor 為 O_NONBLOCK, 告訴 OS 這個 fd 為 non-blocking IO, 呼叫後要能立即返回
兩者作法的優缺點分析已超出本「隨手記」的範圍 (書本作者愛用的大絕), 需要特別注意的是, 設了 O_NONBLOCK 不表示呼叫 read/write 後就結束了。
man 2 read (或 man 2 write) 的 ERRORS 提到:
- EAGAIN The file descriptor fd refers to a file other than a socket and has been marked nonblocking (O_NONBLOCK), and the read would block.
- EAGAIN or EWOULDBLOCK The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK), and the read would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
意思是說:
- 此招對實體檔案無效 (為了檔案讀寫效能, 一次做完可減少硬碟更動讀寫頭的時間)
- 對 socket 仍有可能失效, 記得用 select / epoll 之類的 system call 請系統在有機會完成 non-blocking 操作時通知你。也就是說, 系統只保證此次呼叫不會 block 你, 不保證此次呼叫一定會成功。由開發者持續嘗試呼叫, 總有完成的時候。
您好,如果是平行運算(資源充足)的話,就不太會有"停下來,過一會而再執行"的問題
回覆刪除換句話說,如果今天只執行一個程式,其中它有個sleep(1),我們總不能稱它為非同步吧
以我的理解,同步跟非同步就是"等"跟"不等"的問題
您也寫到"不要等完成後才返回 (即「非同步」)"
所以我們的理解應該是一致的?
另外我想"非同步"只是個廣易的統稱
而non-blocking只是其中一種實作方式
另外像是callback也是一種實作方式
這錯大了,blocking, non-blocking和sync async是兩群不同的概念
刪除blocking non-blocking是指物理意義上的等或不等
舉例來說non-blocking IO是指這一次IO從頭到尾保證constant time回傳
(但他可能只回傳狀態,所以你需要做polling)
sync async是指呼叫API當下等或不等
async不代表你真的不用等,你只是召喚一個替身幫你等或者你現在偷懶不做,事後再做而已
如果你async的去呼叫一個block API
實際上你還是要等的,而且他仍然不保證常數時間內回傳
所以你會發現舉凡async的API通常都有個flush或wait就是在做幫你等完的動作