php-fpm通道,Go语言通道(chan)——goroutine之间通信的管道
Go语言通道(chan)——goroutine之间通信的管道
如果说 goroutine 是 Go语言程序的并发体的话,那么 channels 就是它们之间的通信机制。一个 channels 是一个通信机制,它可以让一个 goroutine 通过它给另一个 goroutine 发送值信息。每个 channel 都有一个特殊的类型,也就是 channels 可发送数据的类型。一个可以发送 int 类型数据的 channel 一般写为 chan int。
Go语言提倡使用通信的方法代替共享内存,当一个资源需要在 goroutine 之间共享时,通道在 goroutine 之间架起了一个管道,并提供了确保同步交换数据的机制。声明通道时,需要指定将要被共享的数据的类型。可以通过通道共享内置类型、命名类型、结构类型和引用类型的值或者指针。
这里通信的方法就是使用通道(channel),如下图所示。
图:goroutine 与 channel 的通信
在地铁站、食堂、洗手间等公共场所人很多的情况下,大家养成了排队的习惯,目的也是避免拥挤、插队导致的低效的资源使用和交换过程。代码与数据也是如此,多个 goroutine 为了争抢数据,势必造成执行的低效率,使用队列的方式是最高效的,channel 就是一种队列一样的结构。
通道的特性
Go语言中的通道(channel)是一种特殊的类型。在任何时候,同时只能有一个 goroutine 访问通道进行发送和获取数据。goroutine 间通过通道就可以通信。
通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。
声明通道类型
通道本身需要一个类型进行修饰,就像切片类型需要标识元素类型。通道的元素类型就是在其内部传输的数据类型,声明如下:
var 通道变量 chan 通道类型
通道类型:通道内的数据类型。
通道变量:保存通道的变量。
chan 类型的空值是 nil,声明后需要配合 make 后才能使用。
创建通道
通道是引用类型,需要使用 make 进行创建,格式如下:
通道实例 := make(chan 数据类型)
数据类型:通道内传输的元素类型。
通道实例:通过make创建的通道句柄。
请看下面的例子:
ch1 := make(chan int) // 创建一个整型类型的通道
ch2 := make(chan interface{}) // 创建一个空接口类型的通道, 可以存放任意格式
type Equip struct{ /* 一些字段 */ }
ch2 := make(chan *Equip) // 创建Equip指针类型的通道, 可以存放*Equip
使用通道发送数据
通道创建后,就可以使用通道进行发送和接收操作。
1) 通道发送数据的格式
通道的发送使用特殊的操作符
通道变量
通道变量:通过make创建好的通道实例。
值:可以是变量、常量、表达式或者函数返回值等。值的类型必须与ch通道的元素类型一致。
2) 通过通道发送数据的例子
使用 make 创建一个通道后,就可以使用
// 创建一个空接口通道
ch := make(chan interface{})
// 将0放入通道中
ch
// 将hello字符串放入通道中
ch
3) 发送将持续阻塞直到数据被接收
把数据往通道中发送时,如果接收方一直都没有接收,那么发送操作将持续阻塞。Go 程序运行时能智能地发现一些永远无法发送成功的语句并做出提示,代码如下:
package main
func main() {
// 创建一个整型通道
ch := make(chan int)
// 尝试将0通过通道发送
ch
}
运行代码,报错:
fatal error: all goroutines are asleep - deadlock!
报错的意思是:运行时发现所有的 goroutine(包括main)都处于等待 goroutine。也就是说所有 goroutine 中的 channel 并没有形成发送和接收对应的代码。
使用通道接收数据
通道接收同样使用
① 通道的收发操作在不同的两个 goroutine 间进行。
由于通道的数据在没有接收方处理时,数据发送方会持续阻塞,因此通道的接收必定在另外一个 goroutine 中进行。
② 接收将持续阻塞直到发送方发送数据。
如果接收方接收时,通道中没有发送方发送数据,接收方也会发生阻塞,直到发送方发送数据为止。
③ 每次接收一个元素。
通道一次只能接收一个数据元素。
通道的数据接收一共有以下 4 种写法。
1) 阻塞接收数据
阻塞模式接收数据时,将接收变量作为
data :=
执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。
2) 非阻塞接收数据
使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式如下:
data, ok :=
data:表示接收到的数据。未接收到数据时,data 为通道类型的零值。
ok:表示是否接收到数据。
非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。如果需要实现接收超时检测,可以配合 select 和计时器 channel 进行,可以参见后面的内容。
3) 接收任意数据,忽略接收的数据
阻塞接收数据后,忽略从通道返回的数据,格式如下:
执行该语句时将会发生阻塞,直到接收到数据,但接收到的数据会被忽略。这个方式实际上只是通过通道在 goroutine 间阻塞收发实现并发同步。
使用通道做并发同步的写法,可以参考下面的例子:
package main
import (
"fmt"
)
func main() {
// 构建一个通道
ch := make(chan int)
// 开启一个并发匿名函数
go func() {
fmt.Println("start goroutine")
// 通过通道通知main的goroutine
ch
fmt.Println("exit goroutine")
}()
fmt.Println("wait goroutine")
// 等待匿名goroutine
fmt.Println("all done")
}
执行代码,输出如下:
wait goroutine
start goroutine
exit goroutine
all done
代码说明如下:
第 10 行,构建一个同步用的通道。
第 13 行,开启一个匿名函数的并发。
第 18 行,匿名 goroutine 即将结束时,通过通道通知 main 的 goroutine,这一句会一直阻塞直到 main 的 goroutine 接收为止。
第 27 行,开启 goroutine 后,马上通过通道等待匿名 goroutine 结束。
4) 循环接收
通道的数据接收可以借用 for range 语句进行多个元素的接收操作,格式如下:
for data := range ch {
}
通道 ch 是可以进行遍历的,遍历的结果就是接收到的数据。数据类型就是通道的数据类型。通过 for 遍历获得的变量只有一个,即上面例子中的 data。
遍历通道数据的例子请参考下面的代码。
使用 for 从通道中接收数据:
package main
import (
"fmt"
"time"
)
func main() {
// 构建一个通道
ch := make(chan int)
// 开启一个并发匿名函数
go func() {
// 从3循环到0
for i := 3; i >= 0; i-- {
// 发送3到0之间的数值
ch
// 每次发送完时等待
time.Sleep(time.Second)
}
}()
// 遍历接收通道数据
for data := range ch {
// 打印通道数据
fmt.Println(data)
// 当遇到数据0时, 退出接收循环
if data == 0 {
break
}
}
}
执行代码,输出如下:
3
2
1
0
代码说明如下:
第 12 行,通过 make 生成一个整型元素的通道。
第 15 行,将匿名函数并发执行。
第 18 行,用循环生成 3 到 0 之间的数值。
第 21 行,将 3 到 0 之间的数值依次发送到通道 ch 中。
第 24 行,每次发送后暂停 1 秒。
第 30 行,使用 for 从通道中接收数据。
第 33 行,将接收到的数据打印出来。
第 36 行,当接收到数值 0 时,停止接收。如果继续发送,由于接收 goroutine 已经退出,没有 goroutine 发送到通道,因此运行时将会触发宕机报错。
php-fpm通道,Go语言通道(chan)——goroutine之间通信的管道相关推荐
- 管道通信C语言,Go语言通道(chan)——goroutine之间通信的管道
如果说 goroutine 是 Go语言程序的并发体的话,那么 channels 就是它们之间的通信机制.一个 channels 是一个通信机制,它可以让一个 goroutine 通过它给另一个 go ...
- java语言中定义的字节输出流_Java语言中的输入输出流包括字节流、字符流、文件流、对象流以及线程之间通信的管道流,【 】包中的类...
[单选题]肥胖是体内中性脂肪过多积聚的表现,超过标准体重多少者为肥胖 A. 超过标准体重10%以上 B. 超过标准体重15%以上 C. 超过标准体重20%以上 D. 超过标准体重25%以上 E. 超过 ...
- Go 学习笔记(24)— 并发(03)[通道特点、通道声明、通道发送/接收/关闭、单向通道]
1. 通道概念 chan 是 Go 语言里面的一个关键宇,是 channel 的简写,翻译为中文就是通道. goroutine 是 Go 语言里面的并发执行体,通道是 goroutine 之间通信和同 ...
- go语言通道插入0_使用Go语言常遇到的问题
这里列举的使用Go语言常遇到的问题都是符合Go语言语法的,可以正常编译,但是可能出现运行结果错误,或者是有资源泄漏的风险. A.1 可变参数是空接口类型 当参数的可变参数是空接口类型时,传入空接口的切 ...
- go语言通道插入0_Go语言入门必知教程-通道
Golang提供了一种称为通道的机制,用于在协程之间共享数据.当函数作为协程执行并发活动时,需要它们共享资源或数据,通道便充当协程之间的管道(管道),提供一种确保同步交换数据的机制. 需要在声明通道时 ...
- go程序设计语言第八章-goroutine和channel
go程序设计语言第八章-goroutine and channel 8.1 goroutines In Go, each concurrently executing activity is call ...
- 图片一:单通道、三通道、灰度图、黑白图、三通道转灰度图(单通道)
图片的概念经常搞不清楚,导致对图片处理很糟糕.感觉还是总结下比较好,省的每次都要找一堆博客看.下面的内容是博主个人理解,不能保证全部正确,如有错误,敬请指出. 1.图片:通常指的是数字图片,数据结构通 ...
- Go语言---并发编程goroutine
在Go语言中并发是通过goroutine实现.goroutine类似于线程,属于用户态线程.Go语言也可以通过channel(管道)与多个goroutine进行通信. goroutine gorout ...
- 图像单通道和4通道转3通道
将图片读进网络可能会因为图片通道不为而报错,这里总结了不同通道处理的情况 单通道转3通道 from PIL import Image import numpy as np im = np.asarra ...
最新文章
- 排查 Node.js 服务内存泄漏,没想到竟是它?
- 免费教材丨第58期:机器学习相关汇总资料大放送(中)
- mysql 分库分表的方法
- zzuli 2269:minval
- 如何在 C# 中使用 MSMQ
- 9050 端口 linux 进程,Linux中查看某个端口占用情况
- Bezier(贝塞尔)曲线的轨迹规划在自动驾驶中的应用(二)
- mysql索引久了需要重新_mysql索引更新要多久
- @RestControllerAdvice 异常分析
- OpenResty安装下载
- anaconda的python文件打包失败的问题解决方案
- 《剑指offer》面试题17——合并两个有序的链表(C++):
- WinForm程序设计-ToolTip控件
- 视频显示器与服务器之间使用什么线连接,显示器连接线有哪些?四种主流连线科普。...
- Java打印斐波那契数列
- 小米摄像头修改wifi
- 项目管理知识体系(PMBOK)
- 《精进:如何成为一个很厉害的人》 采铜
- 苹果手机各种型号图片_一图看懂iPhone各机型机身尺寸大小对比!
- JEECG Excel 工具类
热门文章
- cmake命令的python库的位置参数-DTORCH_PATH
- pte模拟考试_PTE猩际PC版-PTE猩际电脑版下载 v5.6.1--PC6电脑版
- sql server browser启动不了_沐浴书香,润泽童年 | 读书月启动仪式
- 白板机器学习笔记 P13-P21 线性分类
- 计网学习第一章:概述
- Java自动化测试框架-03 - TestNG之Test Group篇 - (详细教程)
- tf卡量产工具万能版_手上还有SD卡/TF卡的小伙伴,这些玩法你有关注过吗
- 小学信息技术用计算机编辑文档教案,小学信息技术《初识文字处理软件》教案.doc...
- w7设置双显示器_怎么在windows7系统下设置双显示器
- java statement 动态参数_java_web学习(九) PreparedStatement动态参数的引入