网站轮播怎么做,石家庄网站建设规划,易记域名网站大全,云南昆州建设工程有限公司网站本篇文章主要介绍Go语言 无缓冲管道和有缓冲管道概念#xff0c;特点及其使用示例。 目录
无缓冲通道
有缓冲的管道
语法
特点
代码示例
未分配空间示例
读取次数不一致示例
For-range遍历
总结 无缓冲通道
sync.RWMutex{}
当涉及到多go程时#xff0c;c语言使用互… 本篇文章主要介绍Go语言 无缓冲管道和有缓冲管道概念特点及其使用示例。 目录
无缓冲通道
有缓冲的管道
语法
特点
代码示例
未分配空间示例
读取次数不一致示例
For-range遍历
总结 无缓冲通道
sync.RWMutex{}
当涉及到多go程时c语言使用互斥量上锁来保持资源同步免资源竞争问题
go语言也支持这种方式但是go语言更好的解决方案是使用管道、通道
使用管道不需要我们去进行加解锁
A 往管道里面写数据 B从管道里面读数据go自动帮我们做好了数据同步。
示例如下
package mainimport (fmttime
)func main() {// 创建管道创建一个装数字的管道 》 channel// strChan : make(chan string) // 装字符串的管道// 装数字的管道使用管道的时候一定要make同map一样否则nil// 此时是无缓冲的管道numChan : make(chan int)// 创建两个go程父写数据子读数据go func() {for i : 0; i 50; i {data : -numChanfmt.Println(data:, data)}}()for i : 0; i 50; i {// 向管道中写入数据numChan - ifmt.Println( 主go程写入数据, i)}time.Sleep(5 * time.Second)
}
运行结果
data: 0主go程写入数据 0主go程写入数据 1
data: 1
data: 2主go程写入数据 2主go程写入数据 3
data: 3
data: 4主go程写入数据 4主go程写入数据 5
data: 5
data: 6主go程写入数据 6主go程写入数据 7
写入和读取无规律可能读在写的前面打印出来。 有缓冲的管道
语法
numsChan : make(chan int,10) 特点
1.当缓冲写满的时候写阻塞当被读取后再恢复写入
2.当缓冲区读取完毕读阻塞
3.如果管道没有使用make分配空间那么管道默认是ni1的读取、写入都会阻塞
4.对一个管道读与写次数必须对等 代码示例
通过创建一个数字管道主go程和一个子go程写入数据另一个子go程读取数据。
需要注意写入数据的总条数与读取数据的总条数相等。
示例如下
package mainimport (fmttime
)func main() {// 有缓冲的管道numChan : make(chan int, 10)go func() {for i : 0; i 50; i {// 从管道中读取数据data : - numChanfmt.Println(子go程1 读取数据 》 data:, data)}}()go func() {for i : 0; i 20; i {// 从管道中读取数据numChan - ifmt.Println(子go程2 写入数据:, i)}}()for i : 20; i 50; i {// 向管道中写入数据numChan - ifmt.Println( 主go程写入数据, i)}time.Sleep(5 * time.Second)
}
运行结果 主go程写入数据 20主go程写入数据 21主go程写入数据 22主go程写入数据 23主go程写入数据 24主go程写入数据 25
子go程2 写入数据: 0
子go程2 写入数据: 1
子go程2 写入数据: 2
子go程2 写入数据: 3主go程写入数据 26
子go程1 读取数据 》 data: 20
子go程1 读取数据 》 data: 0
子go程1 读取数据 》 data: 21
子go程1 读取数据 》 data: 22
子go程1 读取数据 》 data: 23
子go程1 读取数据 》 data: 24
子go程1 读取数据 》 data: 25
子go程1 读取数据 》 data: 26
子go程1 读取数据 》 data: 1
子go程1 读取数据 》 data: 2 未分配空间示例
如果管道不分配空间直接使用会怎么样呢
示例如下
package mainimport (fmttime
)func main() {var names chan string // 默认是nil的go func() {fmt.Println(names:, names)}()names - hello worldtime.Sleep(1 * time.Second)
}
运行结果
$ go run 不分配空间.go
names: nil
fatal error: all goroutines are asleep - deadlock!
解决方法进行分配空间
示例如下
package mainimport (fmttime
)func main() {//var names chan string // 默认是nil的names : make(chan string, 10)go func() {fmt.Println(names:, names)}()names - hello world // 由于names是nil的写操作会阻塞在这里time.Sleep(1 * time.Second)
} 读取次数不一致示例
读当主程序被管道阻塞时那么程序将锁死崩溃
要求我们一定要读写次数保持一致
示例如下
package mainimport (fmttime
)func main() {numsChan1 : make(chan int, 20)//写go func() {for i : 0; i 15; i {// 向管道中写入数据numsChan1 - ifmt.Println( 子go程写入数据, i)}}()// 读for i : 0; i 20; i {// 从管道中读取数据data : - numsChan1fmt.Println(主go程 读取数据 》 data:, data)}time.Sleep(5 * time.Second)
}
当管道的读写次数不一致的时候
如果阻塞在主go程那么程序会崩溃
如果阻塞在子go程那么会出现内存泄漏 For-range遍历
避免出现读写不一致直接使用for-range写法。
示例如下
numsChan2 : make(chan int, 20)//写
go func() {for i : 0; i 15; i {// 向管道中写入数据numsChan2 - ifmt.Println( 子go程写入数据, i)}fmt.Println(数据全部写入完毕准备关闭管道)close(numsChan2)
}()// 读
// 遍历管道时只返回一个值
// for range并不知道管道是否已经写完了所以会一直在这里等待
// 在写入端将管道关闭for range遍历关闭管道时会退出
for v : range numsChan2{fmt.Println(读取数据, v)
}time.Sleep(5 * time.Second) 总结
1.当管道写满了写阻塞
2.当缓冲区读完了读阻塞
3.如果管道没有使用make分配空间管道默认是nil
4.从nil管道读取数据写入数据都会阻塞注意不会崩溃
5.从一个已经colse的管道读取数据时会返回零值不会崩溃
6.像一个已经colse的管道写数据时会崩溃
7.关闭一个已经colse的管道程序会崩溃
8.关闭管道的动作一定要在写端执行不应该放到读端否则写的继续写会崩溃
9.读和写的次数一定要对等否则 在多个go程中资源泄露 在主go程中程序崩溃deadlock。