上篇文章说了一下Go语言协程(goruntine),今天这篇说一下协程间的通信。非常容易理解,它就是通道(channel),它的作用就是可以让多个goruntine之间安全的传值。可以使用make关键字创建一个通道:
test:=make(chan int)
test通道只有两种方法,使用<-接受内容和发送内容,<-在通道左边为接受内容,<-在通道右边为发送内容,写一个例子展示一下通道的接受发送吧:
package main
import "fmt"
func main() {
ch := make(chan string)
go func() {
ch <- "我是协程发送的值"
}()
fmt.Println("我是主线程")
data := <-ch
fmt.Println(data)
fmt.Println("程序执行完毕")
}
在这个例子中的通道是一个有无缓冲的通道,发送和接受是同时发生的,通道中没有容量储存任何数据,没有规定容量,不用像上篇例子写协程中在主线程中等待1秒让协程任务先执行输出,在这个例子中如果协程任务不向通道发送内容,那么主程序接受内容的代码永远会等待这个通道发送数据,直到接受到内容才会运行主程序下面的代码。
缓冲通道
与无缓冲通道相关的就是有缓冲通道,定义缓冲通道需要规定通道的容量,内部的元素先进先出,让我想起了堆栈,堆是先进先出,栈是先进后出。有缓冲的通道也会有两种任务阻塞的状态,一种是通道中没有接受的值,接受操作就会阻塞,另一种就是通道塞满了,发送操作就会阻塞。经典使用场景可以使用for 循环读取或接受通道内容,直到通道关闭:
for x := range ch{
fmt.Println(x)
}
这样只要通道关闭了就停止循环了,不会报错。写一个简单的功能来实现这个功能:
package main
import (
"fmt"
"strconv"
)
func main() {
ch := make(chan string)
go func() {
for i := 0; i <= 10; i++ {
ch <- "发送" + strconv.Itoa(i)
}
close(ch)
}()
fmt.Println("我是主线程")
for x := range ch {
fmt.Println("接受:" + x)
}
fmt.Println("程序执行完毕")
}
这里补充一下关闭通道的知识,使用
close()方法关闭通道。简单直白,跟使用go启动一个协程一样那么简单,
总结
在Go语言通道还有很多用法,现在是初学阶段就了解一下它是干嘛的就行了那,Go语言推荐不要通过共享内存来通信,而应该通过通信来共享内存”,在传统语言多线程想读取修改资源的时候通过对内存进行加锁和解锁来进行通信保证数据安全,而在Go语言通道这里相当于用通道开辟一个共享内存来声明对某个资源控制权,使用通道来进行消息传递,条理更加清晰可靠。