大家好,欢迎来到IT知识分享网。
其实关于 golang 信道网上资料很多很全面了,个人感觉也没什么需要特别注意的坑。但是为了 golang 系列的的完整性,我还是开了这一篇博客,为大家提供一些 golang 使用的例子,多一些参考文档。
在上一篇中我们提到 golang 通过 go 程提供了非常优秀的高并发能力,那么 go 程之间的通信就是通过 channel 来进行的。和 go 程一样,golang 在语法上就支持 channel,golang 为 chennle 专门实现了一种变量类型 chan。可以和创建普通变量一样创建 channel。另外 chan 类型的变量的一个重要特性:线程安全。其他类型变量在高并发场景,如果要直接操作这个变量需要先加锁,chan 则完全避免了这个烦恼。
我们来直接看例子,这个例子时基于上一章的第一个例子做了些许的改动:
package main import ( "fmt" ) func main() { ch := make(chan int) go func(ch chan int) { fmt.Println("Hello, I am a goroutine.") ch <- 0 }(ch) <-ch fmt.Println("Hello, I am the main goroutine.") }
输出:
Hello, I am a goroutine. Hello, I am the main goroutine.
这里我们就没有用到 time.Sleep,在上一章节我们提到如果没有 Sleep 主 go 程就会先退出,还没等子 go 程执行完毕整个程序就结束了。这里我们用来一种比 Sleep 更优雅的方式 chan 使主 go 程阻塞,等等子 go 程想 chan 写入数据,主 go 程收到数据才继续往下执行。这里借助了 channel 另一个比较重要的特性:当 channel 中没有数据,读时就会阻塞;当 channel 满了之后向 channel 写数据也就会阻塞。通过这种方式就能及时知道子 go 程退出了,避免了长时间的等待。
另外需要特别注意的是阻塞发生的时机,下面例子需要实际运行看结果,大家可以自己运行一下对比结果:
package main import ( "fmt" "time" ) func main() { ch := make(chan int) go func(ch chan int) { for { time.Sleep(5 * time.Second) <-ch fmt.Println("子 go 程从 ch 中读到数据") // 把 time.Sleep(5 * time.Second) 挪到这儿试试 } }(ch) fmt.Println("准备向 channel 写入数据") ch <- 0 fmt.Println("写入成功") }
另外在有些情况我们并不希望因为 channel 数据接收端(消费者)的 go 程处理数据过慢而阻塞 channel 数据发送端(生产者)的 go 程,这时候我们可以使用带缓存的 channel。可以使用下面方法创建带缓存的 channel。
ch := make(chan int, 10)
这将会创建一个 10 个缓存空间的 channel。
单方向的 channel
channel 还可以设置成只读或者只写
创建只写 channel:
var ch chan<- int
或者
ch := make(chan<- int, 10)
创建只读 channel
var ch <-chan int
或者
ch := make(<-chan int, 10)
特别注意:如果直接使用单方向的 channel 那么程序必然或阻塞。正确的使用方式是先创建一个正常的 channel,然后在隐式的转为只读和只写,生产者使用只写 channel,消费者使用只读 channel,如下:
package main import ( "fmt" "time" ) func main() { ch := make(chan int, 10) go producer(ch) go consumer(ch) time.Sleep(1 * time.Millisecond) } func producer(ch chan<- int) { a := 10 fmt.Printf("生产者发送数据:%d\n", a) ch <- a } func consumer(ch <-chan int) { a := <-ch fmt.Printf("消费者接收到数据:%d\n", a) }
输出:
生产者发送数据:10 消费者接收到数据:10
在前面第二章节讲过 channel 类型的数据变量事一个引用,这里通过函数传参的方式进行隐式的转换只是作用在了引用本身上,实际转换前和转换后变量对应的底层数据是一样的。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/109111.html