Golang Channel通道使用简介

2023-11-07

Golang Channel通道使用简介

一、channel简介

chan 是 Golang 中内置的数据类型,不像 Mutex 等需要引入,它是 first-class 类型,在 Go 的并发控制中起着相当重要的作用。chan 的思想来自 Tony Hoare 在 1978 年发表的论文 Communicating Sequential Processes, 它提出了一种并发的编程语言,用来描述并发系统中的互动模式,后来逐渐形成了 CSP 并发模式。CSP 模式中存在 Process/Channel 每个 Process 独立运行,多个 Process 之间通过 Channel 通信。

Go 并发控制的核心思想:

Don’t communicate by sharing memory, share memory by communicating. 
即不要通过共享内存来通信,而是要通过通信来共享内存,

前一句话对应传统利用 锁 等方式控制并发,后者就对应 CSP方式,go 中的 goroutine/chan 分别与 CSP 中的 Process/Channel 对应。

二、channel基础知识

基本分类

chan    // 既可以发送数据,又可以接收数据的 channel
chan<-  // 只能接收数据的 channel
<-chan  // 只能发送数据的 channel

channel 是管道,因此一个传输具体类型数据的 channel 声明方式如下:

var ch chan string      // 双向通道, 既可以往 ch 中写,也可以从 ch 中读 string 类型数据
var ch chan<- interface{} 或者 var ch = make(chan<- interface{}) // 只能往 ch 中发送 struct{} 类型数据
var ch <-chan int      或者 var ch make(<-chan int)        // 只能从 ch 中读取 int 数据

// 只读和只写一般用于数据通道,单独使用没有意义,比如:
func main() {
    c := make(chan int)
    go send(c)
    go recv(c)
    time.Sleep( * time.Second)
}
//只能向chan里写数据
func send(c chan<- int) {
    for i := ; i < ; i++ {
        c <- i
    }
}
//只能取channel中的数据
func recv(c <-chan int) {
    for i := range c {
        fmt.Println(i)
    }
}

channel 使用必须初始化,初始化是否指定长度可以分为

ch := make(chan string) // 无缓冲通道
ch := make(chan string, 2)// 有缓冲通道

三、基本使用

1) 发送数据

往 channel 中发送数据使用 “ch<-”,示例如下:

ch <- 10

这里的 ch 的类型是 chan int 或者 chan<- int

2) 接收数据

从 channel 中接收数据使用 “<-ch”,示例如下:

x := <-ch  // 把 ch 中接收到的一条数据赋值给 x
foo(<-ch) // 把 ch 中接收到的一条数据作为函数 foo 的参数
<-ch      // 丢弃一条从 ch 中接收到的数据

从 channel 中接收数据的时候,还可以接收两个值:

x, ok := <-ch

ok 是一个 bool 值,表示是否成功的从 channel 中接收到了数据。如果 ok 是 false,ch 已经被 close,且 ch 中没有缓存数据,那么 x 就是零值。所以,如果 x 是零值,有可能是接收到了零值,也有可能是空的且被 close 的 channel 产生的零值。

3) 其它操作

Go 的内建函数 close、cap、len 都可以操作 channel。close 可以关闭 channel,关闭之后的 channel 无法接收数据;cap 返回 channel 的容量;len 返回 channel 的长度。

发送和接收数据还可以作为 select 语句的 case clause,例如:

func main() {
    var ch = make(chan int, 10)
    for i := 0; i < 10; i++ {
        select {
        case ch <- i:
        case v := <-ch:
            fmt.Println(v)
        }
    }
}

channel 还可以用于 for-range 语句中:

for v := range ch {
    fmt.Println(v)
}

或者是忽略读取的值,只是清空 channel:

for range ch {
}

四、踩坑注意

1) panic 错误

常见的会导致 panic 的三种场景如下:

  • close 为 nil 的 channel
  • close 已经 closed 的 channel
  • send 已经 close 的 channel
2) goroutine 泄露

无缓冲chan的使用,必须要求接收方和发送方都准备好,如果仅仅发送方准备好就发送信息,会导致chan阻塞,例如:

var ch = make(chan int)
ch <- -1
for {
	select {
        case res := <-ch:
		fmt.Println("收到信息",res)
	}
}

该示例中,对于无缓冲信道,在接收者未准备好之前,发送操作是阻塞的.,goroutine 无法退出,进而造成泄露。

解决方案1:让接收者提前做好准备,随时准备接受信息,推荐使用。

var ch = make(chan int)
go func() {
	for {
		select {
		case res := <-ch:
			fmt.Println("收到信息",res)
		}
	}
}()
ch <- -1 

解决方案2:使用有缓冲通道

var ch = make(chan int,1)
ch <- -1
fmt.Println("收到信息", <-ch)
3) 容量导致阻塞

每个缓冲信道,都有容量,当信道里的数据量等于信道的容量后,此时再往信道里发送数据,就失造成阻塞,必须等到有人从信道中消费数据后,程序才会往下进行。

func main() {
	ch1 := make(chan string, 1)

	ch1 <- "hello world"
	ch1 <- "hello China"// 超过容量,排队阻塞

	fmt.Println(<-ch1)
}
4) 持续读无写导致死锁

当程序一直在等待从信道里读取数据,而此时并没有人会往信道中写入数据。此时程序就会陷入死循环,造成死锁。

func main() {
	pipline := make(chan string)
	go func() {
		pipline <- "hello world"
		pipline <- "hello China"
	}()
	for data := range pipline{
		fmt.Println(data)
	}
}

解决:只要在发送完数据后,手动关闭信道,告诉 range 信道已经关闭,无需等待就行。

func main() {
	pipline := make(chan string)
	go func() {
		pipline <- "hello world"
		pipline <- "hello China"
		close(pipline)
	}()
	for data := range pipline{
		fmt.Println(data)
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Golang Channel通道使用简介 的相关文章

随机推荐

  • JavaScript 实现 -- 冒泡排序

    文章目录 冒泡排序 代码实现 冒泡排序过程 时间复杂度 算法稳定性 冒泡排序 冒泡排序 Bubble Sort 也叫气泡排序 泡沫排序 是一种比较简单的排序算法 它通过遍历数组 比较相邻的两个元素 如果前一个元素比后一个元素大 则交换它们的
  • 基于BIO模式下通信项目

    文章目录 功能清单 代码结构 服务端设计 接收多个客户端逻辑 接收登陆消息及监测离线 接收群聊消息 接收私聊消息 代码实现 客户端设计 启动客户端界面 登录 刷新在线 客户端发送消息逻辑 代码实现 功能清单 1 客户端登陆功能 可以启动客户
  • CMake入门学习+实战<三> 静态库与动态库构建

    文章整合自 CMake Practice http sewm pku edu cn src paradise reference CMake 20Practice pdf CMake 官方文档 https cmake org cmake h
  • 讯为IMX6ULL-QT系统移植之交叉编译QT源码和触摸源码

    一 源码下载 QT 官网下载 Index of new archive qt 5 7 5 7 1 二 编译环境 开发环境 Ubuntu18 04 编译器 arm 2014 05 29 arm none linux gnueabi i686
  • What version of SQL Server do I have?(转)

    原文链接 http sqlserverbuilds blogspot com What version of SQL Server do I have This unofficial build chart lists all of the
  • C#值类型构造函数注意事项

    C 语言相比其他支持CLR的语言来说 对于值类型的构造有个特殊的地方 即不允许值类型有无参数的构造函数 所以当一个值类型没有提供任何构造函数的时候 是不能够对字段在定义中进行初始化 如下 public struct Point public
  • 配置Nginx和php-fpm用Sock套接字连接时,找不到php-fpm.sock的原因

    php5 3之后的版本 php fpm conf里的listen的默认配置是127 0 0 1 9000 就不会生成php fpm sock 因此如果需要Nginx里的配置有链接tmp php fpm sock的话 需要将listen的地址
  • ElasticSearch查询工具类分享

    文章目录 1 sql转ES工具 2 Kibana VS Postman ApiPost 3 es json 转java 4 ElasticSearch查询工具类 esHelper 5 在IDE 控制台看到效果如图 前言 最近需要对ES数据进
  • 华为OD机试真题 Java 实现【数字加减游戏】【2023Q1 200分】

    一 题目描述 小明在玩一个数字加减游戏 只使用加法或者减法 将一个数字s变成数字t 每个回合 小明可以用当前的数字加上或减去一个数字 现在有两种数字可以用来加减 分别为a 其中b没有使用次数限制 请问小明最少可以用多少次a 才能将数字s变成
  • Visual Studio 2015 Tools for Unity与VS2015的bug

    之前使用Unity4 X配合的是Visual Studio 2013 Tools与VS2013的时候 是可以打开项目属性的 更换了Unity5 x配合Visual Studio 2015 Tools for Unity与VS2015的时候
  • 基于springboot开发的学生考勤管理系统【毕业论文,源码】

    基于springboot开发的学生考勤管理系统 如需更多资料请前往文章底部获取联系方式 系统设计主要功能 通过市场调研及咨询研究 了解了学生考勤管理系统及管理者的使用需求 于是制定了管理员 教师和学生等模块 功能结构图如下所示 E R图 考
  • 原子操作 CAS

    参考 https zhuanlan zhihu com p 400817892 https www bilibili com read cv10686883 https blog csdn net www dong article deta
  • nacos默认用户名密码_Nacos 权限控制介绍及实战

    转自 阿里巴巴中间件 作者 朱鹏飞 Nacos权限控制设计方案 方案背景 Nacos 自开源依赖 权限控制一直需求比较强烈 这也反应了用户需求将 Nacos 部署到生产环境的需求 最新发布的 Nacos 1 2 0版本已经支持了服务发现和配
  • 文件夹选择对话框 JS实现的两种方案

    文件夹选择对话框 JS实现的两种方案 browseFolder js 该文件定义了BrowseFolder 函数 它将提供一个文件夹选择对话框 以供用户实现对系统文件夹选择的功能
  • 监听器,过滤器,拦截器

    参考博文 文章目录 作用 三者区别 启动顺序 拦截器 简要说明 实现接口 HandlerInterceptor 自定义拦截器 配置拦截器 过滤器 简要说明 在springboot 启动类添加该注解 ServletComponentScan
  • 在word如何显示左侧的索引目录

    https jingyan baidu com article 2c8c281df82bd80008252a23 html
  • 自动控制原理知识点梳理——6.线性系统的校正方法

    主要内容是书上6 1 6 2 6 3 目录 一 系统的设计与校正问题 1 控制系统的性能指标 2 系统带宽的选择 3 校正方法 4 基本控制规律 1 比例 P 控制规律 2 比例 微分 PD 控制规律 3 积分 I 控制规律 4 比例 积分
  • osgEarth的Rex引擎原理分析(六十)TileNode与DrawTileCommand的关系

    目标 五十五 中的问题131 TileNode与DrawTileCommand的关系 DrawTileCommad的几何图形和瓦片编号从TileNode来 最终绘制是用DrawTileCommand的draw函数来实现的 DrawTileC
  • 服务器显示post是什么意思,post请求 post请求是什么

    在HTTP协议的请求类型中 post请求是一个比较常见的请求类型 也是一个使用比较频繁的请求 那么这一个请求到底是什么意思呢 这就是今天我们所要了解的内容 快来一起看一看吧 post请求 post请求的含义 向指定资源提交数据进行处理请求
  • Golang Channel通道使用简介

    Golang Channel通道使用简介 一 channel简介 chan 是 Golang 中内置的数据类型 不像 Mutex 等需要引入 它是 first class 类型 在 Go 的并发控制中起着相当重要的作用 chan 的思想来自