Table of Contents
<span class="ez-toc-title-toggle"><a href="#" class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" aria-label="顯示/隱藏內容目錄"><span class="ez-toc-js-icon-con"><span class=""><span class="eztoc-hide" style="display:none;">Toggle</span><span class="ez-toc-icon-toggle-span"><svg style="fill: #999;color:#999" xmlns="http://www.w3.org/2000/svg" class="list-377408" width="20px" height="20px" viewBox="0 0 24 24" fill="none"><path d="M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z" fill="currentColor"></path></svg><svg style="fill: #999;color:#999" class="arrow-unsorted-368013" xmlns="http://www.w3.org/2000/svg" width="10px" height="10px" viewBox="0 0 24 24" version="1.2" baseProfile="tiny"><path d="M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z"/></svg></span></span></span></a></span>
[Golang] goroutine & channel
Channel
Channel 是 Go 語言中用於 goroutine 之間通信的管道,是 Go 並發編程模型的核心組件之一。
基本概念
Channel 提供了一種 goroutine 之間的通信機制,使一個 goroutine 可以向另一個 goroutine 發送數據,而無需顯式的鎖或條件變量。
類型與創建
// 創建不同類型的 channel
ch1 := make(chan int) // 無緩衝的整數 channel
ch2 := make(chan string, 10) // 有 10 個緩衝區的字符串 channel
ch3 := make(chan interface{}) // 任意類型的 channel發送與接收
// 發送數據
ch <- value
// 接收數據
value := <-ch
value, ok := <-ch // ok 表示 channel 是否已關閉goroutine + Channel 範例:
package main
import "fmt"
import "time"
func main() {
ch1 := make(chan int, 1)
ch2 := make(chan string, 1)
ch3 := make(chan interface{}, 1)
ch1 <- 1 // ch1 緩衝區已滿
// 創建 goroutine 來接收第一個值
go func() {
time.Sleep(2 * time.Second) // 等待1秒
fmt.Println(<-ch1) // 1,此時釋放 ch1 的空間
}()
ch1 <- 3 // 這裡會阻塞,直到上面的 goroutine 從 ch1 接收數據
// 由於上面的 goroutine 有2秒延遲,這里會等待約2秒
ch2 <- "name"
ch3 <- "hi"
fmt.Println(<-ch1) // 3
fmt.Println(<-ch2) // "name"
fmt.Println(<-ch3) // "hi"
}顯示如下:
1
3
name
hi- 範例&說明
package main
import "fmt"
func main() {
// 創建通道
c := make(chan int)
//併發執行
go ifunc(c)
for i := 1; i <= 10; i++{
// 將數據i發送給通道
c <- i
}
// 通道ifunc結束讀取數據
c<- 100
//等於ifunc結束
fmt.Println(<-c)
}
func ifunc(c chan int) {
// 阻塞等待數據
for {
//從通道獲取一個數據
data := <- c
// 當取得的數據為100則結束阻塞
if data == 100{
break
}
// 輸出數據
fmt.Println(data)
}
// 通知main結束
c<-0
}output:
1
2
3
4
5
6
7
8
9
10
0補充:
可以在
fmt.Println(<-c)與fmt.Println(data)之前,print隨便一個數值,
就可以看到,輸出模式取決於 Go 調度器如何在這兩個 goroutine 之間切換
select
select 是 Go 語言中的一個控制結構,專門用於處理多個通道操作。它的主要用途是同時等待多個通道的操作(發送或接收),並在其中一個操作可以進行時執行對應的代碼。
基本語法
select {
case <-chan1:
// 從 chan1 接收到數據時執行
case chan2 <- value:
// 向 chan2 發送數據成功時執行
case x := <-chan3:
// 從 chan3 接收到數據並賦值給 x 時執行
default:
// 沒有通道操作就緒時執行(非阻塞模式)
}package main
import (
"fmt"
"time"
)
func main() {
// 創建兩個通道
ch1 := make(chan string)
ch2 := make(chan string)
// 在一個 goroutine 中,1秒後發送數據到 ch1
go func() {
time.Sleep(1 * time.Second)
ch1 <- "來自通道1的數據"
}()
go func() {
time.Sleep(1 * time.Second)
ch1 <- "來自通道1-1的數據"
}()
// 在另一個 goroutine 中,2秒後發送數據到 ch2
go func() {
time.Sleep(2 * time.Second)
ch2 <- "來自通道2的數據"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "來自通道2-1的數據"
}()
// 使用 select 監聽兩個通道
for i := 0; i < 4; i++ {
select {
case msg1 := <-ch1:
fmt.Println("接收到:", msg1)
case msg2 := <-ch2:
fmt.Println("接收到:", msg2)
case <-time.After(3 * time.Second):
fmt.Println("操作超時")
}
}
}output:
接收到: 來自通道1-1的數據
接收到: 來自通道1的數據
接收到: 來自通道2的數據
接收到: 來自通道2-1的數據