// _通道_ 是連接多個 Go 協(xié)程的管道。你可以從一個 Go 協(xié)程// 將值發(fā)送到通道,然后在別的 Go 協(xié)程中接收。package mainimport "fmt"func main() { // 使用 `make(chan val-type)` 創(chuàng)建一個新的通道。 // 通道類型就是他們需要傳遞值的類型。 messages := make(chan string) // 使用 `channel <-` 語法 _發(fā)送_ 一個新的值到通道中。這里 // 我們在一個新的 Go 協(xié)程中發(fā)送 `"ping"` 到上面創(chuàng)建的 // `messages` 通道中。 go func() { messages <- "ping" }() // 使用 `<-channel` 語法從通道中 _接收_ 一個值。這里 // 將接收我們在上面發(fā)送的 `"ping"` 消息并打印出來。 msg := <-messages fmt.Println(msg)}
# 我們運行程序時,通過通道,消息 `"ping"` 成功的從一個 Go 協(xié)程傳到# 另一個中。$ go run channels.goping# 默認發(fā)送和接收操作是阻塞的,直到發(fā)送方和接收方都準(zhǔn)備完畢。# 這個特性允許我們,不使用任何其它的同步操作,來在程序結(jié)尾等待# 消息 `"ping"`。
// 默認通道是 _無緩沖_ 的,這意味著只有在對應(yīng)的接收(`<- chan`)// 通道準(zhǔn)備好接收時,才允許進行發(fā)送(`chan <-`)。_可緩存通道_// 允許在沒有對應(yīng)接收方的情況下,緩存限定數(shù)量的值。package mainimport "fmt"func main() { // 這里我們 `make` 了一個通道,最多允許緩存 2 個值。 messages := make(chan string, 2) // 因為這個通道是有緩沖區(qū)的,即使沒有一個對應(yīng)的并發(fā)接收 // 方,我們?nèi)匀豢梢园l(fā)送這些值。 messages <- "buffered" messages <- "channel" // 然后我們可以像前面一樣接收這兩個值。 fmt.Println(<-messages) fmt.Println(<-messages)}
$ go run channel-buffering.go bufferedchannel
// 我們可以使用通道來同步 Go 協(xié)程間的執(zhí)行狀態(tài)。這里是一個// 使用阻塞的接受方式來等待一個 Go 協(xié)程的運行結(jié)束。package mainimport "fmt"import "time"http:// 這是一個我們將要在 Go 協(xié)程中運行的函數(shù)。`done` 通道// 將被用于通知其他 Go 協(xié)程這個函數(shù)已經(jīng)工作完畢。func worker(done chan bool) { fmt.Print("working...") time.Sleep(time.Second) fmt.Println("done") // 發(fā)送一個值來通知我們已經(jīng)完工啦。 done <- true}func main() { // 運行一個 worker Go協(xié)程,并給予用于通知的通道。 done := make(chan bool, 1) go worker(done) // 程序?qū)⒃诮邮盏酵ǖ乐?worker 發(fā)出的通知前一直阻塞。 <-done}
$ go run channel-synchronization.goworking...done# 如果你把 `<- done` 這行代碼從程序中移除,程序甚至?xí)?`worker`# 還沒開始運行時就結(jié)束了。
// 當(dāng)使用通道作為函數(shù)的參數(shù)時,你可以指定這個通道是不是// 只用來發(fā)送或者接收值。這個特性提升了程序的類型安全性。package mainimport "fmt"http:// `ping` 函數(shù)定義了一個只允許發(fā)送數(shù)據(jù)的通道。嘗試使用這個通// 道來接收數(shù)據(jù)將會得到一個編譯時錯誤。func ping(pings chan<- string, msg string) { pings <- msg}// `pong` 函數(shù)允許通道(`pings`)來接收數(shù)據(jù),另一通道// (`pongs`)來發(fā)送數(shù)據(jù)。func pong(pings <-chan string, pongs chan<- string) { msg := <-pings pongs <- msg}func main() { pings := make(chan string, 1) pongs := make(chan string, 1) ping(pings, "passed message") pong(pings, pongs) fmt.Println(<-pongs)}
$ go run channel-directions.gopassed message
// Go 的_通道選擇器_ 讓你可以同時等待多個通道操作。// Go 協(xié)程和通道以及選擇器的結(jié)合是 Go 的一個強大特性。package mainimport "time"import "fmt"func main() { // 在我們的例子中,我們將從兩個通道中選擇。 c1 := make(chan string) c2 := make(chan string) // 各個通道將在若干時間后接收一個值,這個用來模擬例如 // 并行的 Go 協(xié)程中阻塞的 RPC 操作 go func() { time.Sleep(time.Second * 1) c1 <- "one" }() go func() { time.Sleep(time.Second * 2) c2 <- "two" }() // 我們使用 `select` 關(guān)鍵字來同時等待這兩個值,并打 // 印各自接收到的值。 for i := 0; i < 2; i++ { select { case msg1 := <-c1: fmt.Println("received", msg1) case msg2 := <-c2: fmt.Println("received", msg2) } }}
# 我們首先接收到值 `"one"`,然后就是預(yù)料中的 `"two"`# 了。$ time go run select.go received onereceived two# 注意從第一次和第二次 `Sleeps` 并發(fā)執(zhí)行,總共僅運行了# 兩秒左右。real 0m2.245s
聯(lián)系客服