golang 信道的讲解与应用–channel(五)

golang 信道的讲解与应用–channel(五)其实关于 golang 信道网上资料很多很全面了 个人感觉也没什么需要特别注意的坑 但是为了 golang 系列的的完整性 我还是开了这一篇博客 为大家提供一些 golang 使用的例子 多一些参考文档

大家好,欢迎来到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

(0)
上一篇 2024-11-14 17:33
下一篇 2024-11-15 10:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信