NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
### channel goroutine运行在相同的地址空间,因此访问共享内存必须做好同步. **goroutine奉行通过通信来共享内存, 而不是共享内存来通信**. 引用类型channel是CSP模式具体实现,用于多个goroutine通讯,其内部实现了同步,确保并发安全. ### channel类型 和map类似,channel也一个对应make创建的底层数据结构的引用. 当我们赋值一个channel或用于函数参数传递时,我们只是拷贝了一个channel引用,因此调用者和被调用者 将引用同一个channel对象.和其它的引用类型一样,channel的零值也是nil . 定义一个channel时,也需要定义发送到channel的值的类型.channel可以使用内置的make()函数来创建: ~~~ make(chan Type) //等价于make(chan Type , 0) make(chan Type,capacity) ~~~ 当capacity = 0 时,channel是无缓冲阻塞读写的,当capacity > 0 时,channel有缓冲,是非阻塞的,直到写满 capacity个元素才阻塞写入. channel通过惭怍福<-来接收和发送数据,发送和接收数据语法: ~~~ channel<-value //发送value到channel <-channe //接收并将其丢弃 x := <-channel //从channel中接收数据,并赋值给x x, ok := <-channel //功能同上,同事检查通道是否已关闭或者是否为空 ~~~ 默认情况下,channel接收和发送数据都是阻塞的,除非另一端你已经准备好,这样就使得goroutine同步变得 更加简单,而不需要显示的lock . ### 实例 ~~~ //全局变量,创建一个channel var ch = make(chan int) //打印机属于公共资源 func printer(str string) { for _, data := range str { fmt.Printf("%c\n", data) time.Sleep(time.Second) } } func person1() { printer("hello") ch <- 1000 //给管道数据,发送 } func person2() { <-ch //从管道接收数据,如果通道没有数据,它就会阻塞 printer("world") } func main() { //新建两个协程,代表两个人,2个人同时使用打印机 go person1() go person2() //不让主协程结束 for { } } ~~~ ~~~ h e l l o w o r l d ~~~ ### 通过channel实现同步和数据交互 ~~~ func main() { ch := make(chan string) defer fmt.Println("主协程执行完毕") go func() { defer fmt.Println("子协程执行完毕") for i := 0; i < 2; i++ { fmt.Println("子协程i = ", i) time.Sleep(time.Second) } }() str := <-ch fmt.Println(str) } ~~~ 死锁,等到子协程执行结束后,管道里面没有人往里面写数据.channel一直是阻塞状态,没有办法往下面继续执行了. ~~~ 子协程i = 0 子协程i = 1 fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan receive]: main.main() /Users/artisan/go/src/learn/main.go:22 +0xe6 ~~~ #### 正确做法 ~~~ func main() { ch := make(chan string) defer fmt.Println("主协程执行完毕") go func() { defer fmt.Println("子协程执行完毕") for i := 0; i < 2; i++ { fmt.Println("子协程i = ", i) time.Sleep(time.Second) } ch <- "我是子协程,工作已完毕" //子协程执行完毕后,将数据写入管道 }() str := <-ch fmt.Println(str) } ~~~ ~~~ 子协程i = 0 子协程i = 1 子协程执行完毕 我是子协程,工作已完毕 主协程执行完毕 ~~~