簡單收發channel
func main() { chanDemo() } func chanDemo() { c := make(chan int) go func() { for { n := <- c // 接收 channel 的數據 fmt.Println(n) } }() // 發送 channel 數據 c <- 1 c <- 2 time.Sleep(time.Millisecond) }
channel 批量收發數據
func main() { chanDemo() } func chanDemo() { // 定義 channel 數組 var channels [10]chan int // 批量收數據 for i := 0; i < 10; i++ { channels[i] = make(chan int) go worker(i,channels[i]) } // 批量發數據 for i := 0; i < 10; i++ { channels[i] <- i + 'a' } time.Sleep(time.Millisecond) } func worker (i int, c chan int){ for { n := <- c // 接收 channel 的數據 fmt.Printf("接收來自 %d 通道,數據%v\n",i,n) } }
channel 通道類型
// 雙向通道 var a chan int // 僅發送類型 var b chan<- int //僅接收類型 var c <-chan int
channel 的緩沖區
func main() { bufferedChan() } func bufferedChan() { c := make(chan int,3) // 給通道設定緩沖區 go worker(0,c) c <- 11 c <- 22 c <- 33 close(c) // 關閉通道 time.Sleep(time.Millisecond) } func worker (i int, c chan int){ // 若從通道收不到數據就退出 //for { // n,ok := <- c // if !ok { // break // } // fmt.Printf("接收來自 %d 通道,數據%v\n",i,n) //} // 同理,若通道有數據就打印 for n := range c { fmt.Printf("接收來自 %d 通道,數據%v\n",i,n) } }
channel 等待所有 goroutine 結束
func main() { chanDemo() } type workStruct struct { in chan int done chan bool } func chanDemo() { // 定義 channel 數組 var channels [10]workStruct for i := 0; i < 10; i++ { channels[i] = workStruct{ in : make(chan int), done: make(chan bool), } } // 批量收數據 for i,w := range channels{ go worker(i,w) } // 批量發數據 for i,w := range channels{ w.in <- 'a' + i } // 當接收完 channels 里面的 done ,表示 channel 執行完畢 for _,w := range channels{ <-w.done close(w.in) close(w.done) } fmt.Printf("執行后續操作") } func worker (i int, c workStruct){ // 同理,若通道有數據就打印 for n := range c.in { fmt.Printf("接收來自 %d 通道,數據%v\n",i,n) c.done <- true } }
WaitGroup 等待所有 goroutine 結束
func main() { chanDemo() } type workStruct struct { in chan int wg *sync.WaitGroup } func chanDemo() { var wg sync.WaitGroup // 定義 channel 數組 var channels [10]workStruct for i := 0; i < 10; i++ { channels[i] = workStruct{ in : make(chan int), wg: &wg, } } wg.Add(10) // 批量收數據 for i,w := range channels{ go worker(i,w) } // 批量發數據 for i,w := range channels{ w.in <- 'a' + i } wg.Wait() fmt.Printf("執行后續操作") } func worker (i int, c workStruct){ // 若通道有數據就打印 for n := range c.in { fmt.Printf("接收來自 %d 通道,數據%v\n",i,n) c.wg.Done() } }
select 接收或發送某個 channel 的值
func main() { var c1, c2 = generator(), generator() for { select { case n := <-c1: fmt.Println("c1里面來了數據", n) case n := <-c1: fmt.Println("走這里", n) case n := <-c2: fmt.Println("c2里面來了數據", n) } } } func generator() chan int { out := make(chan int) go func() { i := 0 for { time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) out <- i i++ } }() return out }
以下描述了 select 語句的語法:
- 每個 case 都必須是一個通信
- 所有 channel 表達式都會被求值
- 所有被發送的表達式都會被求值
- 如果任意某個通信可以進行,它就執行,其他被忽略。
- 如果有多個 case 都可以運行,Select 會隨機公平地選出一個執行。其他不會執行。
否則:- 如果有 default 子句,則執行該語句。
- 如果沒有 default 子句,select 將阻塞,直到某個通信可以運行;Go 不會重新對 channel 或值進行求值。
傳統同步機制
WaitGroup
Cond
Mutex
type atomicInt struct { value int lock sync.Mutex } func (a *atomicInt) increment() { a.lock.Lock() defer a.lock.Unlock() a.value++ } func (a *atomicInt) get() int { a.lock.Lock() defer a.lock.Unlock() return int(a.value) } func main() { var a atomicInt a.increment() go func() { a.increment() }() time.Sleep(time.Millisecond) fmt.Println(a.get()) }