眾所周知,goroutine 是同步但非阻塞的處理單元。golang 調度器很好地處理了非阻塞任務,例如套接字、定時器、信號或來自字符設備的其他事件。但是塊設備 io 或 CPU 敏感任務呢?它們在完成之前不能被中斷,也不能被多路復用。運行 goroutine 的 OS 線程將凍結,直到 goroutine 返回或讓步。在這種情況下,調度粒度變差。當然,你可以在你的代碼中將任務拆分成更小的子任務,例如,不要一次復制 1GB 的文件,而是先復制 10MB,然后再復制 10MB 等,以便其他 goroutine 在相同的操作系統線程有機會運行。CPU 密集型任務的另一個示例:部分壓縮文件并最終合并它們。但這破壞了順序編程的便利性,與OS線程上的OS調度相比,手動調度難以均勻估計。nginx 也有類似的問題,它是多進程程序,一個 CPU 核一個進程,類似于 GOMAXPROCS 的最佳實踐。它引入線程池來處理阻塞任務。也許它對 golang 也有好處。我很好奇為什么golang沒有OS線程API,這對于阻塞任務的goroutine應該是很好的補充。
1 回答

臨摹微笑
TA貢獻1982條經驗 獲得超2個贊
Go 特別選擇不直接向用戶公開 OS 線程,而是選擇了 M:N 線程模型。Go 中的執行單元是 goroutine,它將在 N 個操作系統線程上多路復用。
在極少數情況下,您的 CPU 密集型計算不包含搶占點且操作系統線程不足以繼續運行其他 goroutine,您有 2 個選擇;增加 GOMAXPROCS,或插入runtime.Gosched()
調用以屈服于其他 goroutine。
在阻塞系統調用的情況下,Go 調度器會自動調度一個新的 OS 線程(考慮一個系統調用“阻塞”的時間限制為 20us),并且由于非網絡 IO 是一系列阻塞系統調用,它幾乎總是分配給專用的操作系統線程。由于 Go 已經使用了 M:N 線程模型,用戶通常不知道底層調度程序的選擇,并且可以像運行時使用異步 IO 一樣編寫程序。
考慮使用異步文件 IO有一個懸而未決的問題,但有許多問題需要克服,例如 Linux aio api 中的缺點、跨平臺兼容性以及與可以執行 IO 的所有各種文件系統和設備的交互。
- 1 回答
- 0 關注
- 365 瀏覽
添加回答
舉報
0/150
提交
取消