chan
channel直譯過來就是管道,chan關鍵字定義了goroutine中的管道通信,一個goroutine可以和另一個goroutine進行通信。
chan的讀寫和定義如下:
//define a chan type variable
var ch chan int = make(chan int, 10);
//or
ch := make(chan int, 10);
//write data into chan
ch <- 1;
ch <- 2;
//read data from chan
var x int;
x = <-ch;
x = <-ch;
看下面這段代碼,其中x擷取ch隊頭值,nonempty傳回ch是否非空的:
func main() {
var ch chan int = make(chan int, 10)
ch <- 1
ch <- 2
ch <- 3
close(ch)
var x int
var nonempty bool
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, " length of ch is", len(ch), "nonempty", nonempty)
}
列印結果:

可以看到chan是類似隊列的先進先出類型,每次讀出一個資料後,ch自動彈出該資料不再儲存。
chan一定要初始化才能進行讀寫操作,否則産生死鎖:
package main
import (
"fmt"
)
func main() {
var ch chan int// = make(chan int, 10)
ch <- 1
ch <- 2
ch <- 3
close(ch)
var x int
var nonempty bool
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
}
執行結果,由于所有goroutine已經睡眠,産生死鎖:
select
select會執行第一個可以執行的case語句,會一直監聽直到有第一個可以執行的語句。或者換一種說法,select就是用來監聽和channel有關的IO操作,當 IO 操作發生時,觸發相應的動作。
看這段代碼:
package main
import (
"fmt"
"time"
)
func main() {
var ch chan int = make(chan int, 10)
var x int = 0
var nonempty bool
go func() {
ch <- 1
ch <- 2
ch <- 3
close(ch)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
x, nonempty = <-ch
fmt.Println("x =", x, ", length of ch is", len(ch), ", nonempty", nonempty)
}()
select {
case ch <- x:
fmt.Println("ch write", x)
case x = <-ch:
fmt.Println("ch read", x)
default:
fmt.Println("nothing to do")
}
time.Sleep(time.Second)
}
執行結果,寫入0:
注釋掉第一個case:
select {
// case ch <- x:
// fmt.Println("ch write", x)
case x = <-ch:
fmt.Println("ch read", x)
default:
fmt.Println("nothing to do")
}
執行結果,由于ch為空無法讀出,運作default:
如果有多個io操作都可以執行的話,select會随機選擇一個執行:
select {
// case ch <- x:
// fmt.Println("ch write", x)
case ch <- 4:
fmt.Println("ch write 4")
case ch <- 5:
fmt.Println("ch write 5")
case x = <-ch:
fmt.Println("ch read", x)
default:
fmt.Println("nothing to do")
}
兩種結果: