先初始化一个通道,最大容量是三个元素,当向该通道发送三个值后,该通道已满,再向其发送数据,将会被阻塞。当然,此时你可以从通道中拿出一个数据,那之前的发送数据的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会最先被唤醒。对于接收操作也是如此。