協程
行程和執行緒
行程
? 當運行一個應用程式的時候,作業系統會為這個應用程式啟動一個行程,可以將這個行程看作一個包含了應用程式在運行中需要用到和維護的各種資源的容器,這些資源包括但不限于記憶體地址空間、檔案和設備的句柄以及執行緒
執行緒
? 一個執行緒是一個執行空間,這個空間會被作業系統調度來運行函式中所寫的代碼,每個行程至少包含一個執行緒,每個行程的初始執行緒被稱作主執行緒,因為執行這個執行緒的空間是應用程式的本身的空間,所以當主執行緒終止時,應用程式也會終止,作業系統將執行緒調度到某個處理器上運行,這個處理器并不一定是行程所在的處理器
并發和并行
并發
? 并發是指在一個邏輯處理器同時管理很多事情,這些事情可能只做了一半就被暫停去做別的事情了,golang的并發通過切換多個執行緒打到減少物理處理器空閑等待的目的
并行
? 并行是讓不同的代碼片段同時在不同的物理處理器上執行,大多數情況下,并發的效果比并行好,因為作業系統的硬體的總資源一般很少,但能支持系統同時做很多事情
goroutine協程
在一個協程中運行函式
? 在一個協程中運行一個函式其實很簡單,只要在函式呼叫前加上go即可
// 隨便寫一個demo函式
func Demo01(num int, contain string) {
for i := 0; i < num; i++ {
fmt.Println("這是一個goroutine", contain)
}
}
// 在協程中運行此函式
func main() {
go Demo01(10,"呼叫Demo函式")
fmt.Println("over!")
}
//輸出:
// over!
? 上述代碼由于demo呼叫在協程中進行,所以并不影響主函式的運行,當主函式運行結束之后,代碼運行直接停止,所以協程并沒有輸出任何內容,因此我們可以使用sleep方法讓主函式進入等待狀態
// 隨便寫一個demo函式
func Demo01(num int, contain string) {
for i := 0; i < num; i++ {
fmt.Println("這是一個goroutine", contain)
}
}
// 在協程中運行此函式
func main() {
go Demo01(10,"呼叫Demo函式")
time.Sleep(1000000000)
fmt.Println("over!")
}
//輸出:
// 這是一個goroutine demo呼叫
// 這是一個goroutine demo呼叫
// 這是一個goroutine demo呼叫
// 這是一個goroutine demo呼叫
// 這是一個goroutine demo呼叫
// over!
? 但是這樣子讓主函式等待協程運行,聽起來是個蠻蠢的想法,我們可以使用一個另一種方式解決問題,Waitgroup方法
waitgroup方法
? 我們可以在使用waitgroup方法先實體化一個計數器,wg,在協程中使用wg.done進行操作計數器,從而達到主函式等待協程運行的一個目的
// demo方法
// 同時因為我們要對wg進行操作,因此要把wg的指標傳遞給函式
func Demo01(num int, contain string, wg *sync.WaitGroup) {
// 因為wg,done一般來說都在函式最后使用,因此我們把他放在defer延遲處理函式里面
defer wg.Done()
for i := 0; i < num; i++ {
fmt.Println("這是一個goroutine", contain)
time.Sleep(1000000000)
}
}
// main方法
func main() {
// 實體化計數器wg
var wg sync.WaitGroup
// 要運行兩個goroutine函式
wg.Add(2)
go functions.Demo01(2, "the first goroutine!", &wg)
go functions.Demo01(3, "the second goroutine!", &wg)
// 等待兩個goroutine運行完畢
wg.Wait()
// 執行完畢后再輸出over!
fmt.Println("over!")
}
// 輸出:
// 這是一個goroutine the second goroutine!
// 這是一個goroutine the first goroutine!
// 這是一個goroutine the first goroutine!
// 這是一個goroutine the second goroutine!
// 這是一個goroutine the second goroutine!
// over!
并發執行
? 前文說過,并發執行就是讓協程運行在同一個邏輯處理器上,我們可以在主方法中使用runtime.GOMAXPROCS(1)強制控制在一個邏輯處理器中
// main方法
func main() {
routine.GOMAXPROCS(1)
// 實體化計數器wg
var wg sync.WaitGroup
// 要運行兩個goroutine函式
wg.Add(2)
go functions.Demo01(2, "the first goroutine!", &wg)
go functions.Demo01(3, "the second goroutine!", &wg)
// 等待兩個goroutine運行完畢
wg.Wait()
// 執行完畢后再輸出over!
fmt.Println("over!")
}
? 這樣子會讓處理器在兩個作業中不斷的切換,而并不是真正的同時進行,而真正的同進行,需要并行執行
并行執行
? 并行執行就是讓各個goroutine都在單獨的邏輯處理器中運行,這時runtime.GOMAXPROCS(tmp)中的tmp引數就應給等于你的goroutine個數,同時我們可以使用runtime.NumCPU()來回傳自己電腦中的物理處理器個數,而物理處理器的個數是和自己電腦的處理器掛鉤的
// main方法
func main() {
routine.GOMAXPROCS(2)
fmt.Println(runtime.NumCPU()) // 20
// 實體化計數器wg
var wg sync.WaitGroup
// 要運行兩個goroutine函式
wg.Add(2)
go functions.Demo01(2, "the first goroutine!", &wg)
go functions.Demo01(3, "the second goroutine!", &wg)
// 等待兩個goroutine運行完畢
wg.Wait()
// 執行完畢后再輸出over!
fmt.Println("over!")
}
? 通過并行執行,我們就可以保證不同的協程是同時運行在不同的邏輯處理器當中,可以實行同時運行
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/551276.html
標籤:其他
上一篇:Spring Boot 專案代碼混淆,實戰來了,再也不用擔心代碼泄露了!
下一篇:返回列表
