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