您好,登錄后才能下訂單哦!
這篇文章主要介紹golang中線程和協程有哪些區別,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
區別:線程中數據存儲在內核態的內存空間;而協程中數據存儲在線程提供的用戶態內存空間。線程的任務調度由內核實現,搶占方式,依賴各種鎖;協程的任務調度由用戶態實現的具體調度器進行。
協程
協程,英文名Coroutine。但在 Go 語言中,協程的英文名是:gorutine。它常常被用于進行多任務,即并發作業。沒錯,就是多線程作業的那個作業。
雖然在 Go 中,我們不用直接編寫線程之類的代碼來進行并發,但是 Go 的協程卻依賴于線程來進行。
下面我們來看看它們的區別。
線程的基礎介紹,這里請自行網上搜索文章,因為關于線程的優秀介紹文章已經很多。
協程的特點
這里先直接列出線程的特點,然后從例子中進行解析。
多個協程可由一個或多個線程管理,協程的調度發生在其所在的線程中。
可以被調度,調度策略由應用層代碼定義,即可被高度自定義實現。
執行效率高。
占用內存少。
上面第 1和第 2點
我們來看一個例子: func TestGorutine(t *testing.T) { runtime.GOMAXPROCS(1) // 指定最大 P 為 1,從而管理協程最多的線程為 1 個 wg := sync.WaitGroup{} // 控制等待所有協程都執行完再退出程序 wg.Add(2) // 運行一個協程 go func() { fmt.Println(1) fmt.Println(2) fmt.Println(3) wg.Done() }() // 運行第二個協程 go func() { fmt.Println(65) fmt.Println(66) // 設置個睡眠,讓該協程執行超時而被掛起,引起超時調度 time.Sleep(time.Second) fmt.Println(67) wg.Done() }() wg.Wait()}
上面的代碼片段跑了兩個協程,運行后,觀察輸出的順序是交錯的。可能是:
656612367
意味著在執行協程A的過程中,可以隨時中斷,去執協程行B,協程B也可能在執行過程中中斷再去執行協程A。
看起來協程A 和 協程B 的運行像是線程的切換,但是請注意,這里的 A 和 B都運行在同一個線程里面。它們的調度不是線程的切換,而是純應用態的協程調度。
關于上述代碼中,為什么要指定下面兩行代碼?
runtime.GOMAXPROCS(1)time.Sleep(time.Second)
這需要您去看下 Go 的協程調度入門基礎,請看我之前的另外一篇調度分析文章:
Go 的協程調度機制
如果不設置 runtime.GOMAXPROCS(1),那么程序將會根據操作系統的 CPU 核數而啟動對應數量的 P,導致多個 M,即線程的啟動。那么我們程序中的協程,就會被分配到不同的線程里面去了。為了演示,故設置數量 1,使得它們都被分配到了同一個線程里面,存于線程的協程隊列里面,等待被執行或調度。
協程特點中的第 3和第 4點。
3. 執行效率高。
4. 占用內存少。
因為協程的調度切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數量越多,協程的性能優勢就越明顯。調度發生在應用態而非內核態。
內存的花銷,使用其所在的線程的內存,意味著線程的內存可以供多個協程使用。
其次協程的調度不需要多線程的鎖機制,因為只有一個線程,也不存在同時寫變量沖突,所以執行效率比多線程高很多。
協程和線程的整體對比
比較的點 | 線程 | 協程 |
---|---|---|
數據存儲 | 內核態的內存空間 | 一般是線程提供的用戶態內存空間 |
切換操作 | 操作最終在內核層完成,應用層需要調用內核層提供的 syscall 底層函數 | 應用層使用代碼進行簡單的現場保存和恢復即可 |
任務調度 | 由內核實現,搶占方式,依賴各種鎖 | 由用戶態的實現的具體調度器進行。例如 go 協程的調度器 |
語音支持程度 | 絕大部分編程語言 | 部分語言:Lua,Go,Python … |
實現規范 | 按照現代操作系統規范實現 | 無統一規范。在應用層由開發者實現,高度自定義,比如只支持單線程的線程。不同的調度策略,等等 |
以上是“golang中線程和協程有哪些區別”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。