13.|13. Go极简教程 channel信道
channel 信道的创建
ci := make(chan int)// 整数类型的无缓冲信道
cj := make(chan int, 0)// 整数类型的无缓冲信道
cs := make(chan *os.File, 100)// 指向文件指针的带缓冲信道
channel 是带缓冲和阻塞的信道
默认情况下,在另一端准备好之前,发送和接收都会阻塞。这使得 goroutine 可以在没有明确的锁或竞态变量的情况下进行同步。
ch := make(chan int)
ch <- v// 将 v 送入 channel ch。
v := <-ch// 从 ch 接收,并且赋值给 v。
(“箭头”就是数据流的方向。)
goroutline配合channel, 以实现多线程的同步操作
向缓冲 channel 发送数据的时候,只有在缓冲区满的时候才会阻塞。当缓冲区清空的时候接受阻塞。
package mainimport (
"log"
"time"
)// 声明一个函数,
func add(a int, c chan int) {
log.Println("准备往管道添加:", a)
c <- a
}func main() {
a := []int{1, 2, 3, 4, 5, 6}// 声明了一个管道, 管道长度为0
c := make(chan int)
// 做两个循环, 开启多个协程
for _, v := range a[:len(a)/2] {
go add(v, c)
}
for _, v := range a[len(a)/2:] {
go add(v, c)
}// 上面的chan是阻塞的, 每当这里取出一个值, 上面的协程才会继续再执行一次
var x, y, n int
for i := 0;
i < len(a)/2;
i++ {
n = <-c
log.Println("从管道取出:", n, "并加入到x中")
x += nn = <-c
log.Println("从管道取出:", n, "并加入到y中")
y += n
}time.Sleep(500 * time.Microsecond)
log.Printf("x:%d, y:%d, sum:%d", x, y, x+y)
}
打印的内容(执行的顺序每次不一, 但是sum的总和是一致的):
2018/06/03 15:50:14 准备往管道添加: 6
2018/06/03 15:50:14 从管道取出: 6 并加入到x中
2018/06/03 15:50:14 准备往管道添加: 2
2018/06/03 15:50:14 从管道取出: 2 并加入到y中
2018/06/03 15:50:14 准备往管道添加: 5
2018/06/03 15:50:14 从管道取出: 5 并加入到x中
2018/06/03 15:50:14 准备往管道添加: 1
2018/06/03 15:50:14 准备往管道添加: 3
2018/06/03 15:50:14 从管道取出: 1 并加入到y中
2018/06/03 15:50:14 从管道取出: 3 并加入到x中
2018/06/03 15:50:14 准备往管道添加: 4
2018/06/03 15:50:14 从管道取出: 4 并加入到y中
2018/06/03 15:50:14 x:14, y:7, sum:21
range 和 close 发送者可以 close 一个 channel 来表示再没有值会被发送了。接收者可以通过赋值语句的第二参数来测试 channel 是否被关闭:当没有值可以接收并且 channel 已经被关闭,那么经过
v, ok := <-ch
之后 ok 会被设置为
false
。循环
for i := range c
会不断从 channel 接收值,直到它被关闭。注意: 只有发送者才能关闭 channel,而不是接收者。向一个已经关闭的 channel 发送数据会引起 panic。 还要注意: channel 与文件不同;通常情况下无需关闭它们。只有在需要告诉接收者没有更多的数据的时候才有必要进行关闭,例如中断一个
range
。package mainimport "log"func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0;
i < n;
i++ {
c <- x
x, y = y, x+y
}
// close 关闭一个 channel
// close 只能由发送者(协程的函数)执行
close(c)
}func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)//还要注意: channel 与文件不同;通常情况下无需关闭它们。只有在需要告诉接收者没有更多的数据的时候才有必要进行关闭,例如中断一个 `range`
for v := range c {
log.Println(v)
}
}
参考资料:
http://go-tour-zh.appspot.com/
【13.|13. Go极简教程 channel信道】Go极简教程 继续阅读( 目录)
推荐阅读
- 2.6|2.6 Photoshop操作步骤的撤消和重做 [Ps教程]
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- 剑指|剑指 Offer 13. 机器人的运动范围(dfs,bfs)
- 极简主义|极简主义 简记
- 用npm发布一个包的教程并编写一个vue的插件发布
- 20180322【w4复盘日志】
- 狗狗定点大小便视频教程下载地址
- SwiftUI|SwiftUI iOS 瀑布流组件之仿CollectionView不规则图文混合(教程含源码)
- 【实用教程】4种获取无水印视频素材的方法
- 【糯米糖藕】教程