golang 学习 (八)协程
一:?進程、線程 和 協程 之間概念的區別:
? ? ? ?對于?進程、線程,都是有內核進行調度,有 CPU 時間片的概念,進行?搶占式調度(有多種調度算法)
? ?(補充: 搶占式調度與非搶占(輪詢任務調度)區別在于搶占式調度可以因為優先級高的任務搶占cpu,而輪詢的不能)
對于?協程(用戶級線程),這是對內核透明的,也就是系統并不知道有協程的存在,是完全由用戶自己的程序進行調度的,因為是由用戶程序自己控制,那么就很難像搶占式調度那樣做到強制的 CPU 控制權切換到其他進程/線程,通常只能進行?協作式調度,需要協程自己主動把控制權轉讓出去之后,其他協程才能被執行到。
goroutine 和協程區別:
本質上,goroutine 就是協程。?不同的是,Golang 在 runtime、系統調用等多方面對 goroutine 調度進行了封裝和處理,當遇到長時間執行或者進行系統調用時,會主動把當前 goroutine 的CPU (P) 轉讓出去,讓其他 goroutine 能被調度并執行,也就是 Golang 從語言層面支持了協程。Golang 的一大特色就是從語言層面原生支持協程,在函數或者方法前面加 go關鍵字就可創建一個協程。
其他方面的比較
1. 內存消耗方面
每個 goroutine (協程) 默認占用內存遠比 Java 、C 的線程少。
goroutine:2KB?
線程:8MB
2. 線程和 goroutine 切換調度開銷方面
線程/goroutine 切換開銷方面,goroutine 遠比線程小
線程:涉及模式切換(從用戶態切換到內核態)、16個寄存器、PC、SP...等寄存器的刷新等。
goroutine:只有三個寄存器的值修改 - PC / SP / DX.
二:?進程、線程 和 協程 之間概念的區別:?
線程是操作系統的內核對象,多線程編程時,如果線程數過多,就會導致頻繁的上下文切換,這些 cpu 時間是一個額外的耗費。所以在一些高并發的網絡服務器編程中,使用一個線程服務一個 socket 連接是很不明智的。于是操作系統提供了基于事件模式的異步編程模型。用少量的線程來服務大量的網絡連接和I/O操作。但是采用異步和基于事件的編程模型,復雜化了程序代碼的編寫,非常容易出錯。因為線程穿插,也提高排查錯誤的難度。
? 協程,是在應用層模擬的線程,他避免了上下文切換的額外耗費,兼顧了多線程的優點。簡化了高并發程序的復雜度。
舉個例子,一個高并發的網絡服務器,每一個socket連接進來,服務器用一個協程來對他進行服務。代碼非常清晰。而且兼顧了性能。
那么,協程是怎么實現的呢?
他和線程的原理是一樣的,當 a線程 切換到 b線程 的時候,需要將 a線程 的相關執行進度壓入棧,然后將 b線程 的執行進度出棧,進入 b線程 的執行序列。協程只不過是在 應用層 實現這一點。但是,協程并不是由操作系統調度的,而且應用程序也沒有能力和權限執行 cpu 調度。怎么解決這個問題?
答案是,協程是基于線程的。內部實現上,維護了一組數據結構和 n 個線程,真正的執行還是線程,協程執行的代碼被扔進一個待執行隊列中,由這 n 個線程從隊列中拉出來執行。這就解決了協程的執行問題。那么協程是怎么切換的呢?答案是:golang 對各種 io函數 進行了封裝,這些封裝的函數提供給應用程序使用,而其內部調用了操作系統的異步 io函數,當這些異步函數返回 busy 或 bloking 時,golang 利用這個時機將現有的執行序列壓棧,讓線程去拉另外一個協程的代碼來執行,基本原理就是這樣,利用并封裝了操作系統的異步函數。包括 linux 的 epoll、select 和 windows 的 iocp、event 等。
? 由于golang是從編譯器和語言基礎庫多個層面對協程做了實現,所以,golang的協程是目前各類有協程概念的語言中實現的最完整和成熟的。十萬個協程同時運行也毫無壓力。關鍵我們不會這么寫代碼。但是總體而言,程序員可以在編寫 golang 代碼的時候,可以更多的關注業務邏輯的實現,更少的在這些關鍵的基礎構件上耗費太多精力。
但是由于協程是非搶占式的調度,無法實現公平的任務調用。
盡管,在任務調度上,協程是弱于線程的。但是在資源消耗上,協程則是極低的。一個線程的內存在?MB?級別,而協程只需要?KB?級別。而且線程的調度需要內核態與用戶的頻繁切入切出,資源消耗較高。
我們把協程的基本特點歸納為:
| 1 2 | 1. 協程調度機制無法實現公平調度 2. 協程的資源開銷是非常低的,一臺普通的服務器就可以支持百萬協程。 |
? 那么,近幾年為何協程的概念可以大熱。我認為一個特殊的場景使得協程能夠廣泛的發揮其優勢,并且屏蔽掉了劣勢 --> 網絡編程。與一般的計算機程序相比,網絡編程有其獨有的特點。
| 1 2 3 | 1. 高并發(每秒鐘上千數萬的單機訪問量) 2. Request/Response。程序生命期端(毫秒,秒級) 3. 高IO,低計算(連接數據庫,請求API)。 |
?
轉載于:https://www.cnblogs.com/liufei1983/p/11191970.html
總結
以上是生活随笔為你收集整理的golang 学习 (八)协程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: B. 熟练剖分(tree) (概率DP)
- 下一篇: 基本数据结构—Hash哈希