Go语言入门(22)-通道 channel
通道(channel)可以在多个goroutine之间安全地传递值,它可以用作变量、函数参数、结构体字段等。
如何使用?:
创建通道用make函数,并指定其传输数据的类型:c := make(chan int)
使用左箭头操作符“<-”向通道发送值 or 从通道接受值。例如
向通道发送值: c <- 2 ; 从通道接收值:r := <- c
发送操作会等待,直到另一个goroutine尝试对该通道进行接收操作为止。下面来看一个简单的例程
package mainimport "fmt"func main() {c :=make(chan int)for i := 0;i < 5; i++{go sleepyGopher(i,c)}for i := 0; i < 5; i++ {gopherID := <- cfmt.Println("gopher",gopherID,"has finished sleeping")}}func sleepyGopher(id int,c chan int) {time.Sleep(3 * time.Second)fmt.Println("...",id," sconre ...")c <- id
}
运行逻辑如上图所示。
使用Select处理多个通道:
目的:等待不同类型的值。
介绍一个函数:time.After,返回值是一个通道,该通道在指定时间后会接收到一个值(发送该值的goroutine是Go运行时的一部分)。Select和switch有点像,该语句包含的每个case都持有一个通道,用来发送or接收数据。select会等待直到某个case分支的操作就绪,然后就会执行该case分支。
下面再看一个例程
package mainimport "fmt"func main() {c :=make(chan int)for i := 0;i < 5; i++{go sleepyGopher(i,c)}timeout := time.After(2 * time.Second)for i := 0; i < 5; i++ {select {case gopherID := <- c:fmt.Println("gopher",gopherID,"has finishied sleeping")case <- timeout:fmt.Println("my patience ran out!")return}}
}func sleepyGopher(id int,c chan int) {time.Sleep(time.Duration(rand.Intn(4000)) * time.Millisecond)c <- id
}
需要注意的是:即使已经停止等待goroutine,但只要main函数还没返回,仍在运行的goroutine将会继续占用内存。
nil通道:
如果不使用make初始化通道,那么通道变量的值就是nil(零值)
对nil通道进行发送or接收不会引起panic,但会导致永久阻塞。对通道执行close函数,会引起panic。
nil通道的用处:对于包含select语句的循环,如果不希望每次循环都等待select所涉及的所有通道,那么可以先将某些通道设为nil,等到发送值准备就绪之后,再将通道变成一个非nil值并执行发送操作。