1. 程式人生 > >Go語言程式設計基礎 併發(二)(完結)——range、close、select、sync.Mutex

Go語言程式設計基礎 併發(二)(完結)——range、close、select、sync.Mutex

4 range和close

傳送者可以通過close關閉一個通道來表示沒有需要傳送的值了。接收者可以通過為接收表示式分配第二個引數來測試通道是否被關閉:如果沒有值可以接收且通道已被關閉,那麼執行完

v, ok := <-ch

之後,ok會被設定為false

迴圈for i := range c會不斷從通道接收值,直到它被關閉。

注意:只有傳送者才能關閉通道,而接收者不能。向一個已經關閉的通道傳送資料會引發程式恐慌(panic)。

注意:通道與檔案不同,通常情況下無需關閉它們。只有在必須告訴接收者不再有值需要傳送的時候才有必要關閉,例如終止一個range迴圈。

package main

import "fmt"

func fff(ch chan int)  {
  for i := 0; i < 10; i ++ {
    ch <- i
  }
  close(ch)
}

func main()  {
  ch := make(chan int, 10)
  go fff(ch)
  for i := range ch {
    fmt.Println(i, "success!")
  } 
}

5 select 語句

select 語句使一個Go程可以等待多個通訊操作
select 會阻塞到某個分支可以繼續執行為止,這時就會執行該分支。當多個分支都準備好時會隨機選擇一個執行。

package main

import "fmt"

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.
Println(<-c) } quit <- 0 }() fibonacci(c, quit) }

6 預設選擇

當select中的其他分支都沒有準備好時,default分支就會執行。
為了在嘗試傳送或接收時不發生阻塞,可使用default分支:

select {
case i := <-c
default:
}
package main

import (
	"fmt"
	"time"
)

func main() {
	tick := time.Tick(100 * time.Millisecond)
	boom := time.After(500 * time.Millisecond)
	for {
		select {
		case <-tick:
			fmt.Println("tick.")
		case <-boom:
			fmt.Println("BOOM!")
			return
		default:
			fmt.Println("    .")
			time.Sleep(50 * time.Millisecond)
		}
	}
}

7 sync.Mutex

Go通常使用互斥鎖(Mutex)實現互斥。
Go標準庫提供了sync.Mutex互斥鎖以及兩個方法:Lock、Unlock。
可以在程式碼前呼叫Lock方法,在程式碼後呼叫Unlock方法來保證一段程式碼的互斥執行。也可以使用defer語句來保證互斥鎖一定會被解鎖。

package main

import (
  "fmt"
  "sync"
  "time"
)

type SafeCounter struct {
  v map[string]int
  mux sync.Mutex
}

func (c *SafeCounter) Inc(key string) {
  c.mux.Lock()
  c.v[key]++
  c.mux.Unlock()
}

func (c *SafeCounter) Value(key string) int {
  c.mux.Lock()
  defer c.mux.Unlock()
  return c.v[key]
}

func main() {
  c := SafeCounter{v: make(map[string]int)}
  for i := 0; i < 1000; i++ {
    go c.Inc("somekey")
  }
  time.Sleep(time.Second)
  fmt.Println(c.Value("somekey"))
}

學習源:Go 指南