Go语言学习(十一)| 通道
时间:2022-07-22
本文章向大家介绍Go语言学习(十一)| 通道,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
通道类型的值本身就是并发安全的,这也是 Go 语言自带的、唯一一个可以满足并发安全性的类型。
通道声明及初始化
通道相当于一个先进先出的队列。在声明一个通道类型变量的时候,我们首先要确定该通道类型的元素类型,决定了我们可以通过这个通道传递什么样的数据。
声明并初始化一个通道时需要使用内建函数 make
。 make
第二个参数可选,用于表示通道的容量。
ch := make(chan int, 2)
当容量为0时,该通道为 非缓冲通道
。大于0时为 缓冲通道
。
元素值的发送和接受都需要使用操作符 <-
(也叫接送操作符)。用法如下:
-
ch <-
将元素发送至通道 ch -
<- ch
也被叫做接收表达式,用于表达从该通道接收一个元素值。
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 4//像通道ch 发送一个元素值2
ch <- 3
ch <- 1
elem := <- ch//从通道中接收一个元素值
fmt.Println(elem)//4
fmt.Println(len(ch))//2
}
引发阻塞的操作
缓冲通道
如果通道已满,那么所有的发送到该通道的操作都会被阻塞,直到通道中有元素被接收走。通道会优先通知最早因此等待的那个操作所在的goroutine,再次进行发送。
如果通道已空,那么对它的所有接收操作都会被阻塞,直到通道中有新元素出现。道会优先通知最早因此等待的那个操作所在的goroutine,再次进行接收。
非缓冲通道
无论是发送还是接收,一开始执行就会被阻塞,直到出现配对的操作也开始,才会继续传递。由此可见,非缓冲通道是采用同步的方式进行传递。
值为nil的通道
对值为nil的通道进行发送和接收都会永久阻塞状态。它们所属的goroutine中的代码都不再会执行。
由于通道类型是引用类型,所以它的零值就是 nil 。所以只声明了该类型的变量但是没有用make 初始化时,它的值就会是 nil
引发panic的操作
下边罗列一下会引发 panic
的情况:
- 通道关闭后,继续向它进行发送操作
- 试图关闭一个已经关闭的通道
千万不要让接收方关闭通道,应该让发送方做这件事
单向通道
只能发不能收或者只能收不能发的通道就是单向通道。例:
ch := make(chan<- int, 1)
上述通道表示只能发不能收。简称为 发送通道
通道常用操作
package main
import "fmt"
func main() {
ch := getChan()
for elem := range ch {
fmt.Println(elem)
}
}
func getChan() <-chan int {
ch := make(chan int, 5)
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
return ch
}
下边例子为 select
与通道联合使用
package main
import (
"fmt"
"math/rand"
)
func main() {
channels := [3]chan int {
make(chan int, 1),
make(chan int, 1),
make(chan int, 1),
}
randInt := rand.Intn(3)
fmt.Println("value:", randInt)
channels[randInt] <- randInt
select {
case elem := <-channels[0]:
fmt.Println("first channel, value:", elem)
case elem := <-channels[1]:
fmt.Println("second channel, value:", elem)
case elem := <-channels[2]:
fmt.Println("third channel, value:", elem)
default:
fmt.Println("error")
}
}
select 有默认分支时不会被阻塞。
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int, 1)
time.AfterFunc(time.Second, func() {
close(ch)
})
select {
case _, ok := <-ch://判断通道是否已关闭
if !ok {
fmt.Println("ch is closed")
break
}
}
}
- velocity模板引擎学习(4)-在standalone的java application中使用velocity及velocity-tools
- mac上开启ftp
- Web前端开发的四个阶段
- 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus
- 关于把本地应用封装成windows app发布审核通不过的问题
- java并发编程学习:用 Semaphore (信号量)控制并发资源
- java并发编程学习: ThreadLocal使用及原理
- 使用Autofac IOC组织多项目应用程序
- 国内首个“人工智能与变革管理研究院”成立
- 解决WordPress缩略图插件timthumb不支持站外图片的问题
- 让 http 2来得更猛烈些吧
- SQL Server 2008基于策略的管理
- centos系统安装Python
- rpc框架之 thrift连接池实现
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- React中的setState是异步的吗?
- java安全编码指南之:堆污染Heap pollution
- ECMAScript6基础学习教程(五)对象
- React入门系列(三)创建组件
- prometheus学习笔记(2)-利用java client写入数据
- Vue入门系列(一)Vue技术栈
- Openwrt智能路由系统开发--内容总结
- 干爆红队-爆破CS Teamserver 密码
- 使用Golang免杀Tips
- centos7卸载自带jdk并安装新的jdk
- 即使不懂单元测试,会用这个工具也够了~
- 统计分布讲解
- 使用PyTorch Lightning自动训练你的深度神经网络
- linux防火墙相关配置命令及操作(centos和ubuntu)
- 带你吃透Spring事务7种传播行为 | Spring第45篇