很多人喜欢Go语言,其实是因为Go语言有其独特的语言属性在支撑着其在编程语言界的发展,今天兄弟连Go语言+区块链培训老师给大家介绍一下关于Go语言并发技术3:管道通信,下面我们一起来看一下吧。( http://bt.itxdl.cn/ )
channel 介绍
channel 提供了一种通信机制,通过它,一个 goroutine 可以想另一 goroutine 发送消息。channel 本身还需关联了一个类型,也就是 channel 可以发送数据的类型。例如: 发送 int 类型消息的 channel 写作 chan int 。
channel 创建
channel 使用内置的 make 函数创建,下面声明了一个 chan int 类型的 channel:
ch := make(chan int)
· 1
c和 map 类似,make 创建了一个底层数据结构的引用,当赋值或参数传递时,只是拷贝了一个 channel 引用,指向相同的 channel 对象。和其他引用类型一样,channel 的空值为 nil 。使用 == 可以对类型相同的 channel 进行比较,只有指向相同对象或同为 nil 时,才返回 true
channel 的读写操作
ch := make(chan int)
// write to channel
ch <- x
// read from channel
x <- ch
// another way to read
x = <- chnnel 一定要初始化后才能进行读写操作,否则会永久阻塞。
channel 一定要初始化后才能进行读写操作,否则会永久阻塞。
关闭 channel
golang 提供了内置的 close 函数对 channel 进行关闭操作。
ch := make(chan int)close(ch)
有关 channel 的关闭,你需要注意以下事项:
1. 关闭一个未初始化(nil) 的 channel 会产生 panic
2. 重复关闭同一个 channel 会产生 panic
3. 向一个已关闭的 channel 中发送消息会产生 panic
4. 从已关闭的 channel 读取消息不会产生 panic,且能读出 channel中还未被读取的消息,若消息均已读出,则会读到类型的零值。从一个已关闭的 channel 中读取消息永远不会阻塞,并且会返回一个为
5. false 的 ok-idiom,可以用它来判断 channel 是否关闭
6. 关闭 channel 会产生一个广播机制,所有向 channel 读取消息的 goroutine 都会收到消息
ch := make(chan int, 10)
ch <- 11
ch <- 12
close(ch)
forx := range ch {
fmt.Println(x)
}
x, ok := <- ch
fmt.Println(x, ok)
-----
output:
11
12
0 false
channel 的类型
channel 分为不带缓存的 channel 和带缓存的 channel。
无缓存的 channel
从无缓存的 channel 中读取消息会阻塞,直到有 goroutine 向该 channel 中发送消息;同理,向无缓存的 channel 中发送消息也会阻塞,直到有 goroutine 从 channel 中读取消息。
通过无缓存的 channel 进行通信时,接收者收到数据 happens before 发送者 goroutine 唤醒
有缓存的 channel
有缓存的 channel 的声明方式为指定 make 函数的第二个参数,该参数为 channel 缓存的容量
ch := make(chan int, 10)
· 1
有缓存的 channel 类似一个阻塞队列(采用环形数组实现)。当缓存未满时,向 channel 中发送消息时不会阻塞,当缓存满时,发送操作将被阻塞,直到有其他 goroutine 从中读取消息;相应的,当 channel 中消息不为空时,读取消息不会出现阻塞,当 channel 为空时,读取操作会造成阻塞,直到有 goroutine 向 channel 中写入消息。
ch := make(chan int, 3)
// blocked, read from empty buffered channel
<- ch
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
// blocked, send to full buffered channel
ch <- 4
通过 len 函数可以获得 chan 中的元素个数,通过 cap 函数可以得到 channel 的缓存长度。
实例
通过channel实现同步
导入依赖
import (
"fmt"
"time"
)
//语法点①:创建int类型的无缓存管道//var ch = make(chan int)varch = make(chan int,0)
funcPrinter(str string) {
for_, data := range str {
fmt.Printf("%c", data)
time.Sleep(time.Second)
}
fmt.Printf("\n")
}
func person1() {
//打印完需要7秒钟
//劳资不打印完是不会往管道中塞数据的,阻塞不死你丫的
Printer("今生注定我爱你")
//箭头指向管道内部,写数据
//在打完今生注定我爱你(耗时7秒钟)后,才写入数据
//语法点②:向管道里写数据,无论读写,箭头只能朝左
//语法点⑤:如果管道缓存已满,则阻塞等待至有人取出数据腾出空间,再写入
ch <- 666
}
func person2() {
//箭头指向管道外面,代表从管道中拿出数据,读数据
//语法点③:从管理取出数据,但不不接收
//语法点⑥:管道里没数据时,阻塞死等
<-ch
//语法点④:从管理取出数据,且使用data变量接收
//data:=<-ch
//fmt.Println("读出数据:",data)
//终于妈的可以打印了
Printer("FUCKOFF")
}
func main() {
go person1()
go person2()
//主协程赖着不死
for {
time.Sleep(time.Second)
}
}
通过channel实现同步和数据交互
package main
import (
"fmt"
"time"
)
func main() {
//创建无缓存管道
ch := make(chan string)
//5、主协程结束
defer fmt.Println("主协程也结束")
//子协程负责写数据
go func() {
//3、结束任务
defer fmt.Println("子协程调用完毕")
//1、缓缓打印2次序号
for i := 0; i < 2; i++ {
fmt.Println("子协程 i= ", i)
time.Sleep(time.Second)
}
//2、向管道发送数据
ch <- "我是子协程,工作完毕"
}()
//4、阻塞接收
str := <-ch
fmt.Println("str = ", str)
}
无缓冲的channel
package main
import (
"fmt"
"time"
)
func main() {
//创建一个无缓冲的管道
ch := make(chan int, 1)
//长度0,缓存能力0
fmt.Printf("len(ch) = %d, cap(ch)=%d\n", len(ch), cap(ch))
go func() {
//向管道中存入0,被阻塞,存入1,被阻塞,存入2
for i := 0; i < 3; i++ {
fmt.Println("子协程: i = ", i)
ch <- i
fmt.Println("5秒以内被打印出来给杰神100万!")
}
}()
//睡眠2秒
time.Sleep(5 * time.Second)
//读取0,被阻塞,读取1,被阻塞,读取2
for i := 0; i < 3; i++ {
num := <-ch
fmt.Println("num = ", num)
}
}
有缓存的channel
package main
import (
"fmt"
"time"
)
func main() {
//创建3缓存的管道
ch := make(chan int, 3)
//长度0,缓存能力3(即使没人读,也能写入3个值)
fmt.Printf("len(ch) = %d, cap(ch) = %d\n", len(ch), cap(ch))
//一次性存入3个:012,3456789
go func() {
for i := 0; i < 10; i++ {
ch <- i
fmt.Printf("子协程存入[%d]: len(ch) = %d, cap(ch) = %d\n", i, len(ch), cap(ch))
//time.Sleep(1 * time.Second)
}
}()
//time.Sleep(5 * time.Second)
//一次性读取3个:012,345,678,9
for i := 0; i < 10; i++ {
num := <-ch
fmt.Println("num = ", num)
}
time.Sleep(1*time.Nanosecond)
}
更多区块链视频教程/源码/课件/学习资料-企鹅QUN:591229276
有疑问加站长微信联系(非本文作者)