如果说 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 发送到通道,因此运行时将会触发宕机报错。

管道通信C语言,Go语言通道(chan)——goroutine之间通信的管道相关推荐

  1. php-fpm通道,Go语言通道(chan)——goroutine之间通信的管道

    Go语言通道(chan)--goroutine之间通信的管道 如果说 goroutine 是 Go语言程序的并发体的话,那么 channels 就是它们之间的通信机制.一个 channels 是一个通 ...

  2. go 通道 返回_GCTT 出品 | Go 语言的缓冲通道:提示和技巧

    通道和 goroutine 是 Go 语言基于 CSP( communicating sequential processes ,通信顺序进程)并发机制的核心部分.阅读本文可以学到一些关于channe ...

  3. 单片机modebus RTU通信实现,采用C语言,可适用于单片机,VC,安卓等(转)

    源:单片机modebus RTU通信实现,采用C语言,可适用于单片机,VC,安卓等 //modebus_rtu.c /***************************************** ...

  4. 判断串口通信是否正常c语言,串口通信测试方法

    <串口通信测试方法>由会员分享,可在线阅读,更多相关<串口通信测试方法(6页珍藏版)>请在人人文库网上搜索. 1.串口通信测试方法1 关于串口通信的一些知识:RS-232C是目 ...

  5. socket通信项目开源c语言,优秀的国产高性能TCP/UDP/HTTP开源网络通信框架——HP-Socket...

    介绍 HP-Socket是国人开发的一套高性能的TCP/UDP/HTTP网络通信框架,包含了服务端.客户端以及Agent组件,可用于各种不同应用场景的通信系统,并且提供了C/C++.C#.Delphi ...

  6. c语言系统编程六:Linux进程间通信之无名管道

    Linux进程间通信之无名管道 一 文件描述符复制 1.1 dup函数(复制文件描述符) 1.2 dup2函数(复制文件描述符) 二 无名管道的概述 三 无名管道的特点 四 无名管道的创建和使用 4. ...

  7. go语言之行--golang核武器goroutine调度原理、channel详解

    一.goroutine简介 goroutine是go语言中最为NB的设计,也是其魅力所在,goroutine的本质是协程,是实现并行计算的核心.goroutine使用方式非常的简单,只需使用go关键字 ...

  8. 为什么我们需要一门新语言——Go语言

    编程语言已经非常多,偏性能敏感的编译型语言有 C.C++.Java.C#.Delphi和Objective-C等,偏快速业务开发的动态解析型语言有 PHP.Python.Perl.Ruby.JavaS ...

  9. 脚本语言语言脚本语言:Shell , JavaScript、VBScript、Perl、PHP、Python、Ruby、Lua

    今天一直在研究脚本语言语言之类的问题,上午正好有机会和大家共享一下. 脚本语言:Shell , JavaScript.VBScript.Perl.PHP.Python.Ruby.Lua 工作控制语言和 ...

最新文章

  1. Objective-C 自动生成文档工具:appledoc
  2. [改善Java代码]线程优先级只使用三个等级
  3. 机器人滚边有波浪_汽车开启件机器人滚边缺陷分析与调整
  4. mysqldump表损坏问题
  5. java 通配符 类_关于类:具有多个类的Java泛型通配符
  6. 我都不敢信了 东芝芯片“又”将最后决定
  7. linux7自带haprox版本,CentOS7.4—构建最新版haproxy高可用群集
  8. Android之提示错误Can not perform this action after onSaveInstanceState
  9. 什么是单模单纤/双纤光纤收发器?
  10. k6前级效果器怎么用_新手学习电吉他,效果器应选择单块还是综合?
  11. 【环境搭建002】ubuntu 13 在vm 下的 NFS 搭建
  12. 根据标准word模板生成word文档类库(开源)
  13. LOJ2542 随机游走 Min-Max容斥+树上期望DP
  14. php文章列表源码,抓取文章列表
  15. 隋朝之前,扬州指的是现在的南京
  16. ThinkPHP的CURD操作
  17. 工厂模式类图梳理笔记
  18. Error response from daemon: failed to parse mydockerfile-centos: ENV must have two arguments
  19. java 加权平均_使用Java 8流计算加权平均值
  20. F. Clear the String (区间DP)

热门文章

  1. 低层级GPU虚拟内存管理引论
  2. gpgpu-sim卡分配程序设计实例分析
  3. YOLOv4没交棒,但YOLOv5来了!
  4. 2021年大数据Flink(二十):案例二 基于数量的滚动和滑动窗口
  5. java画笔覆盖在界面_Java实现画图程序和重绘
  6. java.lang.ArithmeticException: divide by zero
  7. java 增强for循环(foreach)
  8. leetcode-160-相交链表(simple)
  9. 超简单的react和typescript和引入scss项目搭建流程
  10. Array 数组去重 总结10方法(7)