認識 Golang 協程

認識 Golang 協程

進程、線程 和 協程 之間概念的區別

進程、線程,都是有內核進行調度,有 CPU 時間片的概念,進行 搶佔式調度。

協程(用戶級線程)完全由用戶自己的程序進行調度(協作式調度),需要協程自己主動把控制權轉讓出去之後,其他協程才能被執行到。

goroutine 和協程區別

本質上,goroutine 就是協程。 不同的是,Golang 在 runtime、系統調用等多方面對 goroutine 調度進行了封裝和處理,當遇到長時間執行或者進行系統調用時,會主動把當前 goroutine 的CPU (P) 轉讓出去,讓其他 goroutine 能被調度並執行,也就是 Golang 從語言層面支持了協程。Golang 的一大特色就是從語言層面原生支持協程,在函數或者方法前面加 go關鍵字就可創建一個協程。

線程是操作系統的內核對象,多線程編程時,如果線程數過多,就會導致頻繁的上下文切換,這些 cpu時間是一個額外的耗費。

協程,是在應用層模擬的線程,他避免了上下文切換的額外耗費,兼顧了多線程的優點。簡化了高併發程序的複雜度。

協程是怎麼實現的呢?

協程是基於線程的。內部實現上,維護了一組數據結構和 n 個線程,真正的執行還是線程,協程執行的代碼被扔進一個待執行隊列中,由這 n 個線程從隊列中拉出來執行。這就解決了協程的執行問題。那麼協程是怎麼切換的呢?答案是:golang 對各種 io函數 進行了封裝,這些封裝的函數提供給應用程序使用,而其內部調用了操作系統的異步 io函數,當這些異步函數返回 busy 或 bloking 時,golang 利用這個時機將現有的執行序列壓棧,讓線程去拉另外一個協程的代碼來執行,基本原理就是這樣,利用並封裝了操作系統的異步函數。包括 linux 的 epoll、select 和 windows 的 iocp、event 等。

小結:在任務調度上,協程是弱於線程的。但是在資源消耗上,協程則是極低的。一個線程的內存在 MB 級別,而協程只需要 KB 級別。而且線程的調度需要內核態與用戶的頻繁切入切出,資源消耗也不小。

更多內容請關注每日編程,每天進步一點。


分享到:


相關文章: