channel可以被看成协程之间通信的管道,跟glibc中进程与进程间通信的管道类似。在golang中要传递某个数据从一个协程到另一个协程,可以将数据封装成一个数据对象,将数据对象的指针传入channel中,另外一个协程从管道中读出这个指针,并处理其指向的对象。Go从语言层面保证同一时间只有一个协程能够访问channel里面的数据。
//声明
var chanName chan chanType
//创建通道,如果只是声明通道为nil,需要创建
chanName = make(chan chanType)
例1:
package main
import (
"fmt"
)
func main() {
var c chan int
if c == nil {
fmt.Println("c is nil ,need make")
}
c = make(chan int)
fmt.Printf("value Type:%T", c)
}
结果:
这样的管道是双向的可以写也可以读
//直接推导类型
chanName:= make(chan chanType)
//读数据从管道中
data := <- chanName
//将数据写到管道中
chanName <- data
例2:
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan bool)
fmt.Println("创建完通道,开始运行")
go func() {
data := <-c
fmt.Println("子goroutine 从通道读数据", data)
time.Sleep(2 * time.Second)
fmt.Println("子goroutine 睡眠结束,开始往通道写数据")
c <- true
}()
c <- false
data := <-c
fmt.Println("主goroutine 从通道读取数据 :", data)
fmt.Println("主goroutine 结束")
}
结果:
通道也可以定义单向的:
chan <- Type 支持写 <- chan Type 支持读
例3:
package main
import (
"fmt"
)
func main() {
c := make(chan int)
go func(ch chan<- int) { //只能写通道不能读通道
ch <- 101
}(c)
data := <-c
fmt.Println("从通道中读数据", data)
}
结果:
//当通道关闭时ok等于false
data, ok := <- chanName
例4:
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
go func(ch1 chan int) {
for i := 0; i < 5; i++ {
time.Sleep(time.Second)
ch1 <- i
}
close(ch1)
}(c)
for {
data, ok := <-c
if ok {
fmt.Println("读取数据:", data, ok)
} else {
fmt.Println("读取完毕", ok)
break
}
}
}
//如果循环读取通道数据可以用range,直到通道关闭
for v := range chanName {
}
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
go func(ch1 chan int) {
for i := 0; i < 5; i++ {
time.Sleep(time.Second)
ch1 <- i
}
close(ch1)
}(c)
for data := range c {
fmt.Println("读取数据:", data)
}
}
go语言中还可以定义缓冲通道:
chanName:= make(chan chanType, capacity)
缓冲通道,写数据时,只有缓冲区满了才会阻塞;读数据时,只有缓冲区空了才会阻塞。
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int, 4)
go func(ch chan int) {
for i := 1; i <= 10; i++ {
time.Sleep(time.Second)
c <- i
}
close(c)
}(c)
for {
data, ok := <-c
if ok {
fmt.Println("读取数据:", data, ok)
} else {
fmt.Println("读取完毕", ok)
break
}
}
}