1. 相關概念:
使用者態:當乙個程序在執行使用者自己的**時處於使用者執行態(使用者態)
核心態:當乙個程序因為系統呼叫陷入核心**中執行時處於核心執行態(核心態),引入核心態防止使用者態的程式隨意的操作核心位址空間,具有一定的安全保護作用。這種保護模式是通過記憶體頁表操作等機制,保證程序間的位址空間不會相互衝突,乙個程序的操作不會修改另乙個程序位址空間中的資料。
使用者態與核心態之間的切換:當在系統中執行乙個程式時,大部分時間都是執行在使用者態下的,在其需要作業系統幫助完成一些使用者態自己沒有特權和能力完成的操作時就會切換到核心態。有以下三種方式:
(1)系統呼叫(中斷)
使用者態程序主動要求切換到核心態的一種方式。
(2)異常
cpu執行時如果發生一些沒有預知的異常,會觸發當前程序切換到處理此異常的核心相關程序中。
(3)外圍裝置的中斷
使用者態程序主動要求切換到核心態的一種方式。
協程:又稱微執行緒,纖程。英文名coroutine。coroutine是一種執行在使用者態的使用者執行緒,類似於 greenthread。協程與執行緒都相互獨立,且有自己的上下文,不同之處在於,協程的切換由其自身控制,而執行緒的切換收到系統排程。
2. csp (通訊順序程序)
csp模型用來描述兩個獨立的併發實體通過共享的通訊channel管道進行通訊的併發模型。
golang借用了csp模型的一些概念如:實體 process,通道 channel,為之實現併發進行了理論支援,實際上並沒有完全實現csp模型的所有理論。process是在go語言上的表現就是goroutine,是實際上併發執行的實體,每個實體之間是通過channel通訊來實現資料共享。
3. channel:同步&傳遞訊息
channel是被單獨建立並且可以在程序之間傳遞,它的通訊模式類似於boss-worker模式,乙個實體通過將訊息傳送到channel中,然後又監聽這個channel的實體處理,兩個實體之間是匿名的,實現原理上其實是乙個阻塞的訊息佇列。、
具體可以分為:有/無快取channel,唯讀channel,只寫channel,雙向channel
寫操作:chan
讀操作:
//4. goroutine:實際併發執行的實體create channel
//unbuffered channel
umbuffer_chan := make(chan int)//
buffered channel
//buffer size = 3
buffer_chan := make(chan int,3)//
read-only channel
read_channel := make(
receive-only channel
receive_channel := make(chan
生產者-消費者sample:
package main
import (
"fmt"
"time")
//生產者
func producer (queue chan
//消費者
func consumer( queue
func main()
在函式或者方法前面加上關鍵字go,就建立了併發執行的goroutine,eg:
go func ()
func test()
// ...
go test()
例項**:
package main //5. golang排程器**包宣告語句。
import (
"fmt"
//系統包用來輸出的
"math/rand""
runtime""
sync""
time")
func main()
}}()
//宣告匿名函式,建立goroutine
go func()
}}()
fmt.println(
"waiting to finish!\n
", )
//等待結束
wg.wait()
fmt.println(
"\nterminate program! \n
", )
}
os在物理處理器上排程執行緒來執行,而golang在邏輯處理器上排程goroutine來執行。每個邏輯處理器都分別繫結到單個作業系統執行緒。
如果建立乙個goroutine並準備執行,這個goroutine就會被放到排程器的全域性執行佇列中。之後,排程器就會將佇列中的goroutine分配給乙個邏輯處理器,並放到這個邏輯處理器對應的本地執行佇列中。本地執行佇列中的goroutine會一直等待,知道自己被分配到相應的邏輯處理器上執行。
其中:m:machine,乙個m直接關聯了乙個核心執行緒。
p:processor,代表了m所需要的上下文環境,也就是處理使用者級**邏輯的處理器。
g:goroutine,本質上是一種輕量級的執行緒--協程。
mpg模型,三者關係的巨集觀圖為:
processor的作用:
當核心執行緒阻塞的時候,由於上下文的存在,我們能夠直接放開其他執行緒,繼續去執行未阻塞的執行緒,例子如下:
如果當前,g0由於i/o,系統呼叫進行了阻塞,這個時候m0就可以放開其他的執行緒:
m0和g0進行系統呼叫,等待返回值,上下文p以及routine佇列交由m1進行執行。當m0執行系統呼叫結束後,m0會嘗試去steal("偷")乙個上下文,如果不成功,m0就把它的g0放到乙個全域性的執行佇列中,然後將自己放到執行緒池或者轉入休眠狀態。
global runqueue是各個上下文p在執行完自己的本地的goroutine runqueue後用來拉取新的goroutine的地方(steal working演算法)。此外,p也會週期性的檢查global runqueue上的goroutine,來防止全域性上的goroutine因為得不到執行而餓死。
Golang非CSP併發模型外的其他並行方法總結
golang最為讓人熟知的併發模型當屬csp併發模型,也就是由goroutine和channel構成的gmp併發模型,具體內容不在贅述了,可以翻回之前的文章檢視。在這裡,要講講golang的其他併發方式。golang不僅可以使用csp併發模式,還可以使用傳統的共享資料的併發模式。這是傳統語言比較常用...
Golang併發模型 select高階
最近公司工作有點多,golang的select高階就這樣被拖沓啦,今天堅持把時間擠一擠,把吹的牛皮補上。前一篇文章 golang併發模型 輕鬆入門select 介紹了select的作用和它的基本用法,這次介紹它的3個高階特性。nil的通道永遠阻塞 如何跳出for selectselect 阻塞 當c...
golang中的併發競爭態
golang程式中併發會引起併發競爭,一起沒理解,為什麼說兩個goroutine訪問共享資源會引發競爭態,我的理解如果只使用乙個邏輯處理器本質上不就是同一時間只有乙個goroutine在跑嗎,為什麼會引發競爭態呢,做了如下實驗,確實存在競爭態 package main import fmt runt...