分享
  1. 首页
  2. 文章

Golang学习笔记--Channel

· · 1132 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

如何定义使用

定义

每个通道都有与之关联的类型。此类型是允许通道传输的数据类型。不允许使用该通道传输其他类型的数据。

通道的零值为nil。零通道没有任何用处,因此必须使用类似于 map 和 slice 的make来定义。

package main
import "fmt"
func main() { 
 var a chan int // 定义 channel
 if a == nil {
 fmt.Println("channel a is nil, going to define it")
 a = make(chan int)
 fmt.Printf("Type of a is %T", a) // 输出Type of a is chan int 
 }
}

使用(接收和发送消息)

data := <- a // read from channel a 
a <- data // write to channel a 

默认情况下,发送和接收到通道处于阻塞状态。当数据发送到通道时,主goroutine将在send语句中被阻塞,直到其他Goroutine从该通道读取数据为止。同样,当从通道读取数据时,将阻止读取,直到某些Goroutine将数据写入该通道为止。

此属性可帮助Goroutines有效通信,而无需使用其他编程语言中很常见的显式锁或条件变量。

一个简单的程序:
程序实现 (1 * 1) + (2 * 2) + (3 * 3) + ... (n * n) + (1 * 1 * 1) + (2 * 2 * 2) + (3 * 3 * 3) + ...(n * n * n)
可以拆成两部分并发执行,一个 goroutine 计算平方和,一个计算立方和

package main
import ( 
 "fmt"
)
func calcSquares(number int, squareop chan int) { 
 sum := 0
 for number != 0 {
 digit := number % 10
 sum += digit * digit
 number /= 10
 }
 squareop <- sum
}
func calcCubes(number int, cubeop chan int) { 
 sum := 0 
 for number != 0 {
 digit := number % 10
 sum += digit * digit * digit
 number /= 10
 }
 cubeop <- sum
} 
func main() { 
 number := 10
 sqrch := make(chan int)
 cubech := make(chan int)
 go calcSquares(number, sqrch)
 go calcCubes(number, cubech)
 squares, cubes := <-sqrch, <-cubech // 利用 channel 使主 goroutine 等待结果 
 fmt.Println("Final output", squares + cubes)
}

死锁

有一个地方需要注意,在使用 channel 时可能会引发死锁,看下面一个例子

func main() { 
 ch := make(chan int)
 ch <- 5 
}

这段程序向 channel 发送数字5,但是没有接收方,所以会一直阻塞

单向通道

上述简单的例子展示了双向 channel 如何使用,但是也可以创建单向通道,即仅发送或接收数据的通道。

// 定义只发送channel
sendch := make(chan<- int)

但是这样做又有什么意义呢,无法从 channel 中读取数据。这是使用 channel 转换。可以将双向通道转换为仅发送或仅接收通道,反之亦然。

// 这里将 channel 转换为单项只发送
func sendData(sendch chan<- int) { 
 sendch <- 10
}
func main() { 
 // 定义一个双向 channel
 chnl := make(chan int)
 go sendData(chnl)
 fmt.Println(<-chnl)
}

关闭通道

发送者可以关闭该通道,以通知接收者该通道将不再发送任何数据。接收器可以在从通道接收数据时使用附加变量,以检查通道是否已关闭。

v, ok := <- ch 

在上面的语句中,如果该值是通过对通道的成功发送操作接收到的,则ok为真。如果ok为假,则表示我们正在从封闭的通道读取数据。从关闭的通道读取的值将是通道类型的零值。例如,如果通道是int通道,则从封闭通道接收的值将为0。

channel 和 for range 可以搭配使用

func producer(chnl chan int) { 
 for i := 0; i < 10; i++ {
 chnl <- i
 }
 close(chnl)
}
func main() { 
 ch := make(chan int)
 go producer(ch)
 for v := range ch { // 若channel 未关闭,则一直取数据
 fmt.Println("Received ",v)
 }
}

如果喜欢,请关注我的公众号,或者查看我的博客 http://packyzbq.coding.me. 我会不定时的发送我自己的学习记录,大家互相学习交流哈~

weixin

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:

查看原文:Golang学习笔记--Channel

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1132 次点击
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏