Skip to content

Channel

  • channel被关闭时,也可以读出值,为chaneel类型的0值
  • channel有带缓冲区和不带缓冲区(相当于缓冲区容量为0)两种类型。当缓冲区已满时会阻塞发送者,当缓冲区已空时会阻塞接受者。
  • channel是线程安全的。

channel定义方法

go
ch := make(chan <type>,<buffer_size>)

buffer_size可以为0,为0时为无缓冲channel,在使用无缓冲channel时,在写数据时必须保证,通道的另外一端正在读取数据,不然会造成死锁情况

go
package main
func main() {
	ch := make(chan int)
	ch <- 1
}

fatal error: all goroutines are asleep - deadlock!

go
package main
func main() {
	ch := make(chan int)
	go func() {
		<-ch 
	}()
	ch <- 1
}

channel使用

for

使用range循环channel会一直循环下去,直到channel关闭,如果chaneel没有关闭,会造成死锁问题

go
package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 10)
	for i := 1; i <= 10; i++ {
		ch <- i
		time.Sleep(500 * time.Millisecond)
	}
	close(ch)
	for i := range ch {
		fmt.Println(i)
	}
}

select

使用select可对多个chaneel进行读取,但是同一时间只能有一个chaneel被读取,如果没有任何一个channel可以被读取,那么select将会被阻塞,如果有default分支将直接执行default分支的内容,select无法循环,只能通过外部添加循环来达到目的

  1. 如果所有等待的channel都被关闭,那么select也将退出阻塞
go
package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(chan int)
	c2 := make(chan int)
	go func() {
		time.Sleep(2 * time.Second)
		c <- 1
	}()
	go func() {
		time.Sleep(1 * time.Second)
		c2 <- 2
	}()

	select {
	case i := <-c:
		fmt.Printf("receive from c: %d\n", i)
	case i := <- c2:
		fmt.Printf("receive from c2: %d\n", i)
	default:
		fmt.Println("default")
	}
}

输出:

default