線程、協程、Goroutine的區別和聯系


線程與協程的區別

  1.  調度上的區別
    • 切換開銷的區別
    • 線程太重,資源占用太高,頻繁創建銷毀會帶來嚴重的性能問題;
    • 協程切換遠比線程小

     2.  協程的好處:

    • 一個協程幾乎就是一個普通的對象,因此可以放心阻塞,一旦阻塞那么讓當前線程執行其他的協程(goroutine)

 

goroutine和協程的區別

  1. goroutine是協程的go語言實現,相當於把別的語言的類庫的功能內置到語言里。從調度上看,goroutine的調度開銷遠遠小於線程調度開銷。
  2. 不同的是:Golang在runtime,系統調用等多方面對goroutine調度進行了封裝和處理,即goroutine不完全是用戶控制,一定程度上由go運行時(runtime)管理,好處:當某goroutine阻塞時,會讓出CPU給其他goroutine。

 

線程和goroutine的區別

  1. OS的線程由OS內核調度,每隔幾毫秒,一個硬件時鍾中斷發到CPU,CPU調用一個調度器內核函數。這個函數暫停當前正在運行的線程,把他的寄存器信息保存到內存中,查看線程列表並決定接下來運行哪一個線程,再從內存中恢復線程的注冊表信息,最后繼續執行選中的線程。這種線程切換需要一個完整的上下文切換:即保存一個線程的狀態到內存,再恢復另外一個線程的狀態,最后更新調度器的數據結構。某種意義上,這種操作還是很慢的。
  2. 從調度上講,線程的調度由 OS 的內核完成;線程的切換需要CPU寄存器和內存的數據交換,在線程切換的過程中需要保存/恢復所有的寄存器信息,比如16個通用寄存器,PC(Program Counter),SP(Stack Pointer),段寄存器等等,從而切換不同的線程上下文。 其觸發方式為 CPU時鍾。而goroutine 的調度 則比較輕量級,由go自身的調度器完成;Go運行的時候包涵一個自己的調度器,這個調度器使用一個稱為一個M:N調度技術,m個goroutine到n個os線程(可以用GOMAXPROCS來控制n的數量),Go的調度器不是由硬件時鍾來定期觸發的,而是由特定的go語言結構來觸發的,他不需要切換到內核語境,所以調度一個goroutine比調度一個線程的成本低很多。其只關心當前go程序內協程的調度;觸發方式為 go內部的事件,如文件和網絡操作垃圾回收,time.sleep,通道阻塞,互斥量操作等。在同一個原生線程里,若當前goroutine不發生阻塞,那么不會主動讓出CPU給其他同一線程的goroutine的。在go程序啟動時,會首先創建一個特殊的內核線程sysmom,負責監控和調度。
  3. 從棧空間上,goroutine的棧空間更加動態靈活。每個OS的線程都有一個固定大小的棧內存,通常是2MB,棧內存用於保存在其他函數調用期間哪些正在執行或者臨時暫停的函數的局部變量。這個固定的棧大小,如果對於goroutine來說,可能是一種巨大的浪費。作為對比goroutine在生命周期開始只有一個很小的棧,典型情況是2KB, 在go程序中,一次創建十萬左右的goroutine也不罕見(2KB*100,000=200MB)。而且goroutine的棧不是固定大小,它可以按需增大和縮小,最大限制可以到1GB。
  4. goroutine沒有一個特定的標識。在大部分支持多線程的操作系統和編程語言中,線程有一個獨特的標識,通常是一個整數或者指針,這個特性可以讓我們構建一個線程的局部存儲,本質是一個全局的map,以線程的標識作為鍵,這樣每個線程可以獨立使用這個map存儲和獲取值,不受其他線程干擾。goroutine中沒有可供程序員訪問的標識,原因是一種純函數的理念,不希望濫用線程局部存儲導致一個不健康的超距作用,即函數的行為不僅取決於它的參數,還取決於運行它的線程標識。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM