Golang的协程(goroutine)和同步机制
1、協程介紹
????????進程和線程都是由操作系統內核進行調度,有 CPU 時間片的概念,進行搶占式調度。
????????協程是用戶級的線程,對內核是透明的,系統并不知道協程的存在,并且協程是非搶占式調度,無法實現公平的任務調用,通常只進行協作式調度,需要協程自己主動把控制權轉讓出去之后,其他協程才能被執行到。
在任務調度上,協程弱于線程;
在資源消耗上,協程則是極低的,一個線程的內存在 MB 級別,而協程只需要 KB 級別。
2、協程的的基本原理
????????協程是基于線程的,二者的原理一樣,線程是在操作系統內核層面實現的,協程是在應用層實現了線程。
????????Go Scheduler會把goroutine調度到邏輯處理器上運行,邏輯處理器會一對一的綁定到操作系統的線程。當goroutine可以運行時,會被放入一個邏輯處理器的待執行隊列中;當goroutine遇到長時間執行或執行了一個阻塞的系統調用時(如打開文件),Go Scheduler會將這個邏輯處理器與線程分離,并將另一個線程綁定到這個邏輯處理器,之后從待執行隊列中選擇下一個goroutine來運行,原來的goroutine保存到待執行隊列等待調用(邏輯處理器是不動的)。
????????每一個goroutine是一個獨立的執行單元,相較于每個OS線程固定分配2M內存的模式,goroutine的棧采取了動態擴容方式, 初始時僅為2KB,隨著任務執行按需增長,最大可達1GB,且由golang的調度器 Go Scheduler 來調度。此外,GC還會周期性地將不再使用的內存回收,收縮棧空間。
????????Go Scheduler調度器能管理所有被創建的 goroutine 并為其分配執行時間。Go Scheduler能將語言運行時的邏輯處理器與操作系統的線程一一綁定,并會全面的控制哪個 goroutine 要在哪個邏輯處理器上運行。
3、Goroutine同步機制
Goroutine提供了一種傳統的同步機制——對共享資源加鎖。
(1)原子函數能夠以很底層的加鎖機制來同步訪問整型變量和指針。
atomic.AddInt64(&counter, 1),強制同一時刻只能有一個 goroutine 運行并完成這個加法操作,還有LoadInt、StoreInt等。
(2)互斥鎖用于在代碼上創建一個臨界區,保證同一時間只有一個 goroutine 可以
執行這個臨界區里的代碼。
(3)通道
使用原子函數和互斥鎖能夠保證對共享資源的安全訪問以及消除競爭狀態;
使用通道,通過發送和接收需要共享的資源,在goroutine 之間進行同步。
無緩沖的通道(unbuffered channel):指在接收前沒有能力保存任何值的通道。這種類型的通
道要求發送goroutine 和接收goroutine 同時準備好,才能完成發送和接收操作,如果兩個goroutine
沒有同時準備好,通道會導致先執行發送或接收操作的goroutine阻塞等待。
有緩沖的通道(buffered channel):是一種在被接收前能存儲一個或者多個值的通道。不強制要求goroutine 之間必須同時完成發送和接收。只有在通道沒有可用緩沖區容納被發送的值時,發送動作才會阻塞;只有在通道中沒有要接收的值時,接收動作才會阻塞。
4、多線程-〉異步編程-〉協程
????????線程是操作系統的內核對象,多線程編程時,如果線程數過多,就會導致頻繁的上下文切換,這些 cpu 時間是一個額外的耗費。
????????于是操作系統提供了基于事件模式的異步編程模型,用少量的線程來服務大量的網絡連接和I/O操作,但是采用異步和基于事件的編程模型,復雜化了程序代碼的編寫,非常容易出錯,再加上線程穿插,也提高排查錯誤的難度。
????????協程是在應用層模擬的線程,避免了上下文切換的額外耗費,兼顧了多線程的優點,簡化了高并發程序的復雜度。
5、協程為什么大熱?
????????主要用于網絡編程,其獨有的特點。高并發(每秒鐘上千數萬的單機訪問量),程序生命期短(毫秒,秒級) 高IO,低計算(連接數據庫,請求API)。
6、實際應用
????????在一個函數調用前加上go關鍵字,這次調用就會在一個新的goroutine中并發執行,當被調用的函數返回時,這個goroutine也自動結束。需要注意的是,如果這個函數有返回值,那么這個返回值會被丟棄。
????????
總結
以上是生活随笔為你收集整理的Golang的协程(goroutine)和同步机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是 “马太效应” ?
- 下一篇: 耗费 7.5 亿做的“垃圾”,被 3 个