Go中线程和协程的区别
1. 協(xié)程是什么 ?
在go語言中,協(xié)程被認為是輕量級的線程, 和線程不同的是,操作系統(tǒng)內(nèi)核 感知不到協(xié)程的存在, 協(xié)程的管理依賴于Go語言運行時自身提供的調(diào)度器 同時Go語言中的協(xié)程是從屬于某一個線程的.在這里提出一個問題 : **為什么Go語言需要在線程的基礎(chǔ)上抽象出協(xié)程的概念, 而不是直接操作線程 ? **
回答這個問題就需要深入的了解線程與協(xié)程的區(qū)別
1.1 調(diào)度方式
協(xié)程是用戶態(tài)的。協(xié)程的管理依賴Go語言運行時的調(diào)度器。
同時,Go語言中的協(xié)程是從屬于某一個線程的,協(xié)程與線程的對應(yīng)關(guān)系為M:N,即多對多 .
如圖所示, Go語言調(diào)度器可以將多個協(xié)程調(diào)度到一個線程中,一個協(xié)程也可能切換到多個線程中執(zhí)行。
1. 2 上下文切換的速度
上下文指的是什么 ?
舉個例子 :
當某個線程占用CPU時間過長時, 操作系統(tǒng)的調(diào)度器就會強制下線依此來保證每個線程在一段時間內(nèi)運行的時間差別不大的. 那么此時進行調(diào)度, 就需要發(fā)生上下文的切換, 因為我們下次再運行這個線程時, 需要記錄上一次運行的各種條件. 例如記錄上一次的重要寄存器值, 進程狀態(tài)等等. 這些都存儲在線程控制塊中(TCB).
上下文更為淺顯的意思就是 : 所需要依賴的環(huán)境, 這次的線程退出我們需要記錄其重要的值和信息以便下次再上CPU時, 可以從上一次的末尾開始, 就不必重新開始執(zhí)行. 新上來的線程, 也需要加載上一次執(zhí)行的各種數(shù)據(jù)以便這次執(zhí)行更方便
線程的調(diào)度, 需要操作系統(tǒng)狀態(tài)的轉(zhuǎn)換, 發(fā)送調(diào)度, 需要從用戶態(tài)轉(zhuǎn)變?yōu)閮?nèi)核態(tài), 當切換到下一個要執(zhí)行的線程時, 又需要從內(nèi)核態(tài)轉(zhuǎn)變?yōu)橛脩魬B(tài)
==================================================
從這里我們就可以開始講一下線程和協(xié)程這兩者之間的上下文切換速度
協(xié)程的速度要快于線程 其原因在于協(xié)程切換不用經(jīng)過操作系統(tǒng)用戶態(tài)與內(nèi)核態(tài)的切換 并且Go語言中的協(xié)程切換只需要保留極少的狀態(tài)和寄存器變量值 而線程切換會保留額外的寄存器變量值(例如浮點數(shù)寄存器)1.3 調(diào)度的策略不同
線程的調(diào)度在大部分時間是搶占式的,操作系統(tǒng)調(diào)度器為了均衡每個線程的執(zhí)行周期,會定時發(fā)出中斷信號強制執(zhí)行線程上下文切換。
而Go語言中的協(xié)程在一般情況下是協(xié)作式調(diào)度的,當一個協(xié)程處理完自己的任務(wù)后,可以主動將執(zhí)行權(quán)限讓渡給其他協(xié)程。這意味著協(xié)程可以更好地在規(guī)定時間內(nèi)完成自己的工作,而不會輕易被搶占。當一個協(xié)程運行了過長時間時,Go語言調(diào)度器才會強制搶占其.
1.4 棧空間大小
我們知道,線程是有固定的棧的,基本都是2MB,當然,不同系統(tǒng)可能大小不太一樣,但是的確都是固定分配的。這個棧用于保存局部變量,用于在函數(shù)切換時使用。但是對于goroutine這種輕量級的協(xié)程來說,一個大小固定的棧可能會導致資源浪費:比如一個協(xié)程里面只print了一個語句,那么棧基本沒怎么用;當然,也有可能嵌套調(diào)用很深,那么可能也不夠用。
??所以go采用了動態(tài)擴張收縮的策略:初始化為2KB,最大可擴張到1GB。
總結(jié)
以上是生活随笔為你收集整理的Go中线程和协程的区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go语言defer详解
- 下一篇: Go语言线程与协程之间的关系之GMP模型