Golang利用channel協(xié)調(diào)協(xié)程的方法詳解
前言
go 當中的并發(fā)編程是通過goroutine
來實現(xiàn)的,利用channel(管道)
可以在協(xié)程之間傳遞數(shù)據(jù),實現(xiàn)協(xié)程的協(xié)調(diào)與同步。
使用
新建一個管道,使用make channel
來構(gòu)建
// 構(gòu)建一個緩存長度為8 的管道 ch := make(chan int ,8) // 寫入 ch <- 10 // 取出 number := <-ch // 關(guān)閉 close(ch)
注意: 取數(shù)據(jù)的時候,如果沒得取,會阻塞代碼的執(zhí)行,如果一直沒有取到,那就是死鎖
實現(xiàn)生產(chǎn)者消費者模式
兩個生產(chǎn)者者協(xié)程和一個消費者協(xié)程
使用waitGroup
func main() { ch := make(chan int, 100) wg := sync.WaitGroup{} wg.Add(2) // 生產(chǎn)者 go func() { defer wg.Done() // 寫入數(shù)據(jù) for i := 0; i < 10; i++ { ch <- i } }() // 生產(chǎn)者 go func() { defer wg.Done() // 寫入數(shù)據(jù) for i := 0; i < 10; i++ { ch <- i } }() wg2 := sync.WaitGroup{} wg2.Add(1) // 消費者 go func() { sum := 0 fmt.Printf("sum %d \n", sum) for { // 這里會等待 temp, ok := <-ch // close 并且 管道為空,ok = false if !ok { break } else { sum += temp } } fmt.Printf("sum %d \n", sum) wg2.Done() }() // 等待倆生產(chǎn)者結(jié)束 wg.Wait() // 生產(chǎn)數(shù)據(jù)之后,消費者也并行讀完了,此時可以關(guān)閉 管道 來 跳出for循環(huán)了 close(ch) // 等待消費者協(xié)程結(jié)束 wg2.Wait() }
使用管道則將wg2相關(guān)的代碼改掉
func main() { //... //... ch2 := make(chan struct{}, 0) go func() { sum := 0 fmt.Printf("sum %d \n", sum) for { // 這里會等待 temp, ok := <- ch // close 并且 管道為空,ok = false if !ok { break } else { sum += temp } } fmt.Printf("sum %d \n", sum) ch2 <- struct{}{} }() // 等待倆生產(chǎn)者結(jié)束 wg.Wait() // 關(guān)閉管道 close(ch) // 等待消費者協(xié)程結(jié)束 <-ch2 }
實戰(zhàn)面試題: 「交替打印數(shù)字和字母」
題目
使用兩個 goroutine
交替打印序列,一個 goroutine
打印數(shù)字, 另外一個 goroutine
打印字母, 最終效果如下:
12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728
解題思路
利用channel的 阻塞 來協(xié)調(diào)線程,達到線程交叉執(zhí)行的效果。
代碼
func main() { letter, number := make(chan bool), make(chan bool) wait := sync.WaitGroup{} go func() { i := 1 for { if <-number { fmt.Print(i) i++ fmt.Print(i) i++ letter <- true } } }() wait.Add(1) go func() { // 獲得ASCII碼 i := 'A' for { if <-letter { // 當前已經(jīng)超過Z時,無需再打印 if i > 'Z' { // 停止等待,并且跳出循環(huán) wait.Done() break } // 將ASCII碼強轉(zhuǎn)成字母輸出 fmt.Print(string(i)) i++ fmt.Print(string(i)) i++ number <- true } } }() // 放行數(shù)字打印的阻塞 number <- true // 等待關(guān)閉主線程 wait.Wait() }
其實完全也可以將waitGroup
換成管道
func main() { letter, number := make(chan bool), make(chan bool) // 再定義一個管道來等待,替代waitGroup的作用 wait := make(chan bool) // 打印數(shù)字 go func() { i := 1 for { if <-number { fmt.Print(i) i++ fmt.Print(i) i++ letter <- true } } }() // 打印字母 go func() { // 獲得ASCII碼 i := 'A' for { if <-letter { if i > 'Z' { wait <- true break } // 將ASCII碼強轉(zhuǎn)成字母輸出 fmt.Print(string(i)) i++ fmt.Print(string(i)) i++ number <- true } } }() number <- true // 等待管道取值 <- wait }
到此這篇關(guān)于Golang利用channel協(xié)調(diào)協(xié)程的方法詳解的文章就介紹到這了,更多相關(guān)Golang channel協(xié)調(diào)協(xié)程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang用melody搭建輕量的websocket服務(wù)的示例代碼
在Go中,可以使用gin和melody庫來搭建一個輕量級的WebSocket服務(wù),gin是一個流行的Web框架,而melody是一個用于處理WebSocket的庫,本文給大家演示如何使用gin和melody搭建WebSocket服務(wù),感興趣的朋友一起看看吧2023-10-10go select編譯期的優(yōu)化處理邏輯使用場景分析
select 是 Go 中的一個控制結(jié)構(gòu),類似于用于通信的 switch 語句。每個 case 必須是一個通信操作,要么是發(fā)送要么是接收。接下來通過本文給大家介紹go select編譯期的優(yōu)化處理邏輯使用場景分析,感興趣的朋友一起看看吧2021-06-06Go?實現(xiàn)?WebSockets和什么是?WebSockets
這篇文章主要介紹了Go?實現(xiàn)?WebSockets和什么是?WebSockets,WebSockets?是構(gòu)建實時應(yīng)用程序的第一大解決方案,在線游戲、即時通訊、跟蹤應(yīng)用程序等,下文相關(guān)內(nèi)容介紹需要的小伙伴可以參考一下2022-04-04詳解Go中g(shù)in框架如何實現(xiàn)帶顏色日志
當我們在終端上(比如Goland)運行g(shù)in框架搭建的服務(wù)時,會發(fā)現(xiàn)輸出的日志是可以帶顏色的,那這是如何實現(xiàn)的呢?本文就來和大家簡單講講2023-04-04