先初始化一個通道,最大容量是三個元素,當向該通道發送三個值後,該通道已滿,再向其發送數據,將會被阻塞。當然,此時你可以從通道中拿出一個數據,那之前的發送數據的goroutine會被喚醒。看一下下面的程序:
// 85_chanbase1
package main
import (
"fmt"
"time"
)
var strChan = make(chan string, 3)
func main() {
synChan1 := make(chan struct{}, 1)
synChan2 := make(chan struct{}, 2)
go func() { // 用於演示接收操作
<-synChan1
fmt.Println("Received a sync signal and wait a second ... [receiver]")
time.Sleep(time.Second)
for {
if elem, ok := <-strChan; ok {
fmt.Println("Received: ", elem, "[receiver]")
} else {
break
}
}
fmt.Println("Stopped. [receiver]")
synChan2 <- struct{}{}
}()
go func() { //用於演示發送操作
for _, elem := range []string{"a", "b", "c", "d"} {
strChan <- elem
fmt.Println("Sent: ", elem, "[sender]")
if elem == "c" {
synChan1 <- struct{}{}
fmt.Println("Sent a sync signal. [sender]")
}
}
fmt.Println("Wait 2 second...[sender]")
time.Sleep(time.Second * 2)
close(strChan)
synChan2 <- struct{}{}
}()
<-synChan2
<-synChan2
fmt.Println("Hello World!")
}
運行結果:
Sent: a [sender]
Sent: b [sender]
Sent: c [sender]
Sent a sync signal. [sender]
Received a sync signal and wait a second ... [receiver]
Sent: d [sender]
Wait 2 second...[sender]
Received: a [receiver]
Received: b [receiver]
Received: c [receiver]
Received: d [receiver]
Stopped. [receiver]
Hello World!
其中,syncChan2,這個通道純粹是爲了不讓主goroutine過早結束運行,一旦主goroutine運行結束,go程序的運行也就結束了。在main函數的最後試圖從synChan2接收值兩次,在這兩次接收都成功完成之前,主goroutine會阻塞於此。把syncChan的容量設定爲2,這是因爲main函數中起用了兩個goroutine,這樣一來他們可以不受干擾的向synChan2發送值。一旦那兩個goroutine都向syncChan2發送了值,主goroutine就會恢復運行,但隨後又會結束運行。
注意,程序中的struct{}成爲空結構體類型,在go語言中,空結構體類型的變量是不會佔用內存的,並且所有該類型的變量都擁有相同的內存地址。建議用於傳遞“信號”的通道都可以以struct{}作爲元素類型,除非需要傳遞更多的信息。
注意點:
1、試圖向一個已關閉的通道發送元素值,會立即引發一個運行時恐慌
2、如果有多個goroutine因像一個已滿的通道發送元素值而被阻塞,那麼而當該通道有多餘空間時,最早被阻塞的那個goroutine會最先被喚醒。對於接收操作也是如此。