日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Golang 并发Groutine实例解读(一)

發(fā)布時間:2025/5/22 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Golang 并发Groutine实例解读(一) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Go語言的并發(fā)和并行

不知道你有沒有注意到一個現(xiàn)象,還是這段代碼,如果我跑在兩個goroutines里面的話:

var quit chan int = make(chan int)func loop() {for i := 0; i < 10; i++ {fmt.Printf("%d ", i)}quit <- 0 }func main() {// 開兩個goroutine跑函數(shù)loop, loop函數(shù)負責打印10個數(shù) go loop()go loop()for i := 0; i < 2; i++ {<- quit} }

我們觀察下輸出:

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

這是不是有什么問題??

以前我們用線程去做類似任務的時候,系統(tǒng)的線程會搶占式地輸出, 表現(xiàn)出來的是亂序地輸出。而goroutine為什么是這樣輸出的呢?

goroutine是在并行嗎?

我們找個例子測試下:

package mainimport "fmt" import "time"var quit chan intfunc foo(id int) {fmt.Println(id)time.Sleep(time.Second) // 停頓一秒quit <- 0 // 發(fā)消息:我執(zhí)行完啦! }func main() {count := 1000quit = make(chan int, count) // 緩沖1000個數(shù)據(jù)for i := 0; i < count; i++ { //開1000個goroutine go foo(i)}for i :=0 ; i < count; i++ { // 等待所有完成消息發(fā)送完畢。<- quit} }

讓我們跑一下這個程序(之所以先編譯再運行,是為了讓程序跑的盡量快,測試結(jié)果更好):

go build test.go time ./test ./test 0.01s user 0.01s system 1% cpu 1.016 total

我們看到,總計用時接近一秒。 貌似并行了!

我們需要首先考慮下什么是并發(fā), 什么是并行

并行和并發(fā)

從概念上講,并發(fā)和并行是不同的, 簡單來說看這個圖片

  • 兩個隊列,一個Coffee機器,那是并發(fā)
  • 兩個隊列,兩個Coffee機器,那是并行

那么回到一開始的疑問上,從上面的兩個例子執(zhí)行后的表現(xiàn)來看,多個goroutine跑loop函數(shù)會挨個goroutine去進行,而sleep則是一起執(zhí)行的。

這是為什么?

默認地,?Go所有的goroutines只能在一個線程里跑?。

也就是說, 以上兩個代碼都不是并行的,但是都是是并發(fā)的。

如果當前goroutine不發(fā)生阻塞,它是不會讓出CPU給其他goroutine的, 所以例子一中的輸出會是一個一個goroutine進行的,而sleep函數(shù)則阻塞掉了 當前goroutine, 當前goroutine主動讓其他goroutine執(zhí)行, 所以形成了邏輯上的并行, 也就是并發(fā)。

真正的并行

為了達到真正的并行,我們需要告訴Go我們允許同時最多使用多個核。

回到起初的例子,我們設置最大開2個原生線程, 我們需要用到runtime包(runtime包是goroutine的調(diào)度器):

import ("fmt""runtime" )var quit chan int = make(chan int)func loop() {for i := 0; i < 100; i++ { //為了觀察,跑多些fmt.Printf("%d ", i)}quit <- 0 }func main() {runtime.GOMAXPROCS(2) // 最多使用2個核 go loop()go loop()for i := 0; i < 2; i++ {<- quit} }

這下會看到兩個goroutine會搶占式地輸出數(shù)據(jù)了。

我們還可以這樣顯式地讓出CPU時間:

func loop() {for i := 0; i < 10; i++ {runtime.Gosched() // 顯式地讓出CPU時間給其他goroutinefmt.Printf("%d ", i)}quit <- 0 }func main() {go loop()go loop()for i := 0; i < 2; i++ {<- quit} }

觀察下結(jié)果會看到這樣有規(guī)律的輸出:

0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9

其實,這種主動讓出CPU時間的方式仍然是在單核里跑。但手工地切換goroutine導致了看上去的“并行”。

runtime調(diào)度器

runtime調(diào)度器是個很神奇的東西,但是我真是但愿它不存在,我希望顯式調(diào)度能更為自然些,多核處理默認開啟。

關(guān)于runtime包幾個函數(shù):

  • Gosched?讓出cpu

  • NumCPU?返回當前系統(tǒng)的CPU核數(shù)量

  • GOMAXPROCS?設置最大的可同時使用的CPU核數(shù)

  • Goexit?退出當前goroutine(但是defer語句會照常執(zhí)行)

總結(jié)

我們從例子中可以看到,默認的, 所有g(shù)oroutine會在一個原生線程里跑,也就是只使用了一個CPU核。

在同一個原生線程里,如果當前goroutine不發(fā)生阻塞,它是不會讓出CPU時間給其他同線程的goroutines的,這是Go運行時對goroutine的調(diào)度,我們也可以使用runtime包來手工調(diào)度。

?

本文開頭的兩個例子都是限制在單核CPU里執(zhí)行的,所有的goroutines跑在一個線程里面,分析如下:

  • 對于代碼例子一(loop函數(shù)的那個),每個goroutine沒有發(fā)生堵塞(直到quit流入數(shù)據(jù)), 所以在quit之前每個goroutine不會主動讓出CPU,也就發(fā)生了串行打印
  • 對于代碼例子二(time的那個),每個goroutine在sleep被調(diào)用的時候會阻塞,讓出CPU, 所以例子二并發(fā)執(zhí)行。

轉(zhuǎn)載于:https://www.cnblogs.com/liuzhongchao/p/9528155.html

總結(jié)

以上是生活随笔為你收集整理的Golang 并发Groutine实例解读(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。