Golang 通道 Chan 详解(3)

tech2026-09-21  0

接收元素

怎么接收

elem := <- ch 如果当前通道中没有任何值,那么当前goroutine会被迫进入Gwaiting状态。什么时候唤醒: 直到ch中有新的元素才会被唤醒ch通道被关闭时会里面结束, 并且elem会被赋予该通道元素类型的零值。 elem, ok := <- ch 如果当前通道中没有任何值,那么当前goroutine会被迫进入Gwaiting状态。什么时候唤醒: 直到ch中有新的元素才会被唤醒, ok = truech通道被关闭时会立马结束, 并且elem会被赋予该通道元素类型的零值, ok = false

ps: 试图从一个未被初始化的chan(也就是值为nil的chan)哪里接收元素值,会造成当前goroutine的永久阻塞

如果试图向一个已经关闭的chan接收元素值

chan缓冲空间有值,读取值chan缓冲空间没有值,立马结束当前操作, 并且elem会被赋予该通道元素类型的零值, ok = false

如果有多个goroutine因为向同一个已空的chan接收元素值而被阻塞,那么当该chan中有多余值的时候,最早被阻塞的goroutine最先被唤醒。go运行时系统每次只唤醒一个goroutine

规则

对于一个缓冲通道:

发送操作会使通道复制被发送的元素。如果通道的缓冲空间满了而无法立即复制,则阻塞进行发送操作的goroutine。接收操作会使通道给出一个已发给它的元素值的副本。如果因为通道的缓冲空间已空而无法给出,则阻塞进行接收操作的goroutine。一般情况下,接收方会从通道持有的缓冲中得到元素值在通道完全复制一个元素值之前,没有goroutine能够从通道接收到这个元素值的副本。

发送元素

ch <- 1 + 6

如果当前chan中还没有满

先计算出(1 + 6)得到7,然后将7发送到chan中

如果当前chan没有缓冲空间了:

该goroutine就会被阻塞,直到从该通道中接收一个元素值之后,这个goroutine才会被唤醒并完成发送操作。

如果试图向一个已经关闭的chan发送元素值,会引发一个panic

如果有多个goroutine因为向同一个已满的chan发送元素值而被阻塞,那么当该chan中有多余空间的时候,最早被阻塞的goroutine最先被唤醒。go运行时系统每次只唤醒一个goroutine

package main import ( "fmt" _ "hash/crc32" "time" ) /* struct{}代表的是不包含任何字段的结构体类型。在go语言中,空结构体类型的变量是不占用任何内存空间的, 并且所有该类型的变量都拥有相同的内存地址。建议用于传递“信号”的通道都用struct{]作为元素类型,除非 需要传递更多的信息 */ func main(){ strChan := make(chan interface{}, 3) // 用于传递数据 syncChan1 := make(chan struct{}, 1) // 用于通知接收线程 syncChan2 := make(chan struct{}, 2) // 避免主线程退出,因为需要等待两个协程完成,因此缓冲区设置为2 go func() { <- syncChan1 fmt.Println("Received a sync signal and wait a second ... [receive]") time.Sleep(time.Second) for { if elem, ok := <- strChan; ok { fmt.Println("Received:", elem, "[receive]") }else{ break } } fmt.Println("Stopped [receiver]") syncChan2 <- struct{}{} }() go func() { for _, elem := range []string{"a","b","c","d"} { strChan <- elem fmt.Println("Send:", elem, "[sender]") time.Sleep(time.Second) if elem == "c" { syncChan1 <- struct{}{} fmt.Println("Send a sync signal [sender]") } } fmt.Println("Wait 2 second ... [sender]") time.Sleep(2 * time.Second) close(strChan) syncChan2 <- struct{}{} }() <-syncChan2 <-syncChan2 }

最新回复(0)