前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Go 开发常用操作技巧--channel

Go 开发常用操作技巧--channel

作者头像
微客鸟窝
发布于 2023-01-09 11:21:03
发布于 2023-01-09 11:21:03
54800
代码可运行
举报
文章被收录于专栏:Go语言指北Go语言指北
运行总次数:0
代码可运行

在 Go 语言中,提倡使用通信来共享内存,而不是通过共享内存来通信,这里的通信就是通过 channel 发送接收消息的方式进行数据传递,而不是通过修改同一个变量。所以在数据流动、传递的场景中要考虑优先使用 channel,它是并发安全的,性能也不错。

channel 声明

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ch := make(chan string)
  • 使用 make 函数
  • chan 是关键字,表示 channel 类型,chan 是一个集合类型
  • string 表示 channel 里存放数据的类型

在声明 channel 时,需要指定被共享的数据类型,其中可以通过 channel 共享的类型有 内置类型、命名类型、结构类型和引用类型的值或指针。

channel 使用

chan 只有发送和接收两种操作:

发送:<-chan //向chan内发送数据 接收:chan-> //从chan中获取数据

channel 分为有缓冲和无缓冲两种,下面来分别介绍下。

无缓冲 channel

无缓冲 channel,通道的容量是0,它不能存储数据,只是起到了传输的作用,所以无缓冲 channel 的发送和接收操作是同时进行的。

示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
 "fmt"
)

func main() {
 ch := make(chan string)
 go func(){
  fmt.Println("微客鸟窝")
  ch <- "执行完毕"
 }()

 fmt.Println("我是无尘啊")
 value := <-ch
 fmt.Println("获取的chan的值为:",value)
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
我是无尘啊
微客鸟窝
获取的chan的值为: 执行完毕

有缓冲 channel

在声明的时候,我们可以传入第二个参数,即「channel容量大小」,这样就是创建了一个有缓冲 channel。

  • 有缓冲 channel 内部有一个队列
  • 发送操作是向队列尾部追加元素,如果队列满了,则阻塞等待,直到接收操作从队列中取走元素。
  • 接收操作是从队列头部取走元素,如果队列为空,则阻塞等待,直到发送操作向队列追加了元素。
  • 可以通过内置函数 cap() 来获取 channel 的容量,通过内置函数 len() 获取 channel 中元素个数。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ch := make(chan int,3)
ch <- 1
ch <- 2
fmt.Println("容量为",cap(ch),"元素个数为:",len(ch))
//打印结果:容量为 3 元素个数为:2

关闭 channel

使用内置函数 close(ch)

对端可以判断channel是否关闭

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if num,ok := <- ch;ok == true{
 //如果对端已经关闭,ok-->false
 //如果对端没有关闭,ok-->true
}

也可以使用range 替代ok

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//当channel关闭时,range方式会将里面剩余的数据全部读取完成,再退出
//ch不能替换为<-ch ; 
for num := range ch{
  fmt.Println("读到数据:",num)
}

channel 关闭了就不能再向其发送数据了,否则会引起 panic 异常。 可以从关闭了的 channel 中接收数据,如果没数据,则接收到的是元素类型的零值。

单向 channel

只能发送或者只能接收的 channel 为单向 channel。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
send := make(ch<- int) //只能发送数据给channel
receive := make(<-ch int) //只能从channel中接收数据

示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
 "fmt"
)
//只能发送通道
func send(s chan<- string){
 s <- "微客鸟窝"
}
//只能接收通道
func receive(r <-chan string){
 str := <-r
 fmt.Println("str:",str)
}
func main() {
 //创建一个双向通道
 ch := make(chan string)
 go send(ch)
 receive(ch)
}

//运行结果: str: 微客鸟窝

实战技巧

控制 goroutine 并发的数量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
func main(){
 m1 := make(chan bool)
 go func() {
   for{
   select {
   case <-m1:
    fmt.Println("close")
    return
   case <-time.After(time.Millisecond*10000):
    fmt.Println("-----")
   }
  }
 }()

 // 控制 goroutine 并发的数量
 limit := make(chan bool,3)
 wg := sync.WaitGroup{}
 for i :=0;i<10;i++{
  limit <- true
  wg.Add(1)
  go func(i int) {
   defer func() {
    <- limit
    wg.Done()
   }()
   //HandleLogic()
   fmt.Println(i)
  }(i)
 }
 wg.Wait()

 m1 <- true
 close(m1)
}

for select 无限循环模式

一般是和 channel 组合完成任务,格式为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for { //for 无限循环,或者使用 for range 循环
  select {
    //通过 channel 控制
    case <-done:
      return
    default:
      //执行具体的任务
  }
}

这种是 for + select 多路复用的并发模式,哪个 case 满足条件就执行对应的分支,直到有满足退出的条件,才会退出循环。没有退出条件满足时,则会一直执行 default 分支。

select timeout 模式

假如一个请求需要访问服务器获取数据,但是可能因为网络问题而迟迟获取不到响应,这时候就需要设置一个超时时间:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
 "fmt"
 "time"
)

func main() {
 result := make(chan string)
 timeout := time.After(3 * time.Second) //3秒后超时
 go func() {
  //模拟网络访问
  time.Sleep(5 * time.Second)
  result <- "服务端结果"
 }()
 for {
  select {
  case v := <-result:
   fmt.Println(v)
  case <-timeout:
   fmt.Println("网络访问超时了")
   return
  default:
   fmt.Println("等待...")
   time.Sleep(1 * time.Second)
  }
 }
}

运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
等待...
等待...
等待...
网络访问超时了

select timeout 模式核心是通过 time.After 函数设置的超时时间,防止因为异常造成 select 语句无限等待。 注意:不要写成这样 case <- time.After(time.Second), 这样是本次监听动作的超时时间,意思就说,只有在本次 select 操作中会有效,再次 select 又会重新开始计时,但是有default ,每次都会走到 default,那case 超时操作,肯定执行不到了。


图片及部分相关技术知识点来源于网络搜索,侵权删!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微客鸟窝 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
TiKV源码解析系列文章(二十)Region Split源码解析
在学习了之前的几篇 raft-rs,raftstore 相关文章之后(如 Raft Propose 的 Commit 和 Apply 情景分析,Raftstore 概览等),raft-rs 以及 raftstore 的流程大家应该基本了解了。其中 raft-rs 解决的是单个 Raft group(即单个 Region) 的问题,raftstore 解决的是多个 Raft group (即多个 Region)的问题。Split 和 Merge 则是 raftstore 多个 Raft group 所独有的操作。TiKV 中的 Split 能把一个 Region 分裂成多个 Region,Merge 则能把 Range 相邻的 2 个 Region 合成一个 Region。本文接下来要介绍的是 Split 的源码。
CNCF
2020/09/04
6510
TiKV源码解析系列文章(二十)Region Split源码解析
TiKV 源码解析系列文章(二十一)Region Merge 源码解析
Region Merge 是 Range 相邻的两个的 Region 合并的过程,我们把一个 Region 称为 Source Region,另一个称为 Target Region,在 Merge 过程结束后,Target Region 管理的 Range 会扩大到 Source Region 的部分,Source Region 则被删除。
PingCAP
2020/12/17
1.1K0
TiKV 源码解析系列文章(二十一)Region Merge 源码解析
TiKV 源码解析系列文章(十八)Raft Propose 的 Commit 和 Apply 情景分析
在学习了 前面的文章 之后,相信大家已经对 TiKV 使用的 Raft 核心库 raft-rs 有了基本的了解。raft-rs 实现了 Raft Leader election 和 Log replication 等核心功能,而消息的发送、接收、应用到状态机等操作则需要使用者自行实现,本文将要介绍的就是 TiKV 中这些部分的处理过程。
PingCAP
2020/03/24
9190
TiKV 源码解析系列文章(十八)Raft Propose 的 Commit 和 Apply 情景分析
TiKV 源码阅读三部曲(二)读流程
TiKV 是一个支持事务的分布式 Key-Value 数据库,目前已经是 CNCF 基金会 的顶级项目。
PingCAP
2022/10/27
2610
TiKV 源码解析系列文章(一)序
TiKV 是一个支持事务的分布式 Key-Value 数据库,有很多社区开发者基于 TiKV 来开发自己的应用,譬如 titan、tidis。尤其是在 TiKV 成为 CNCF 的 Sandbox 项目之后,吸引了越来越多开发者的目光,很多同学都想参与到 TiKV 的研发中来。这时候,就会遇到两个比较大的拦路虎:
PingCAP
2019/01/28
1.5K0
TiKV Raft Store 内存管理的原理与实现丨TiKV 源码解读(二十三)
内存管理是数据库系统不可忽视的核心问题之一,它直接影响系统的性能、稳定性和成本效率。
PingCAP
2024/11/27
1610
TiKV Raft Store 内存管理的原理与实现丨TiKV 源码解读(二十三)
TiKV 源码阅读三部曲(三)写流程
TiKV 是一个支持事务的分布式 Key-Value 数据库,目前已经是 CNCF 基金会 的顶级项目。
PingCAP
2022/11/16
7590
TiDB 最佳实践系列(四)海量 Region 集群调优
在 TiDB 的架构中,所有的数据按照 range 划分成一个个 Region 分布在多个 TiKV 实例上。随着数据的写入,一个集群中会产生上百万,甚至千万个 Region。而量变引起质变,单 TiKV 实例上过多的 Region 无疑会带来比较大的负担,进而影响整个集群的性能表现。
PingCAP
2019/10/24
8870
TiKV 源码解析系列文章(十九)read index 和 local read 情景分析
在上篇文章中,我们讲解了 Raft Propose 的 Commit 和 Apply 情景分析,相信大家对 TiKV 的 Raft 写流程有了大概了解。这篇文章将尝试向大家较为完整的介绍下 TiKV 中的 Raft 读流程的实现,特别是 read index 和 lease read(或称 local read)。关于 read index 和 lease read 的介绍和理论基础,请大家参阅 TiKV 功能介绍 - Lease Read 或者 Raft 论文第 6.4 节,不在这里赘述。
PingCAP
2020/08/27
7800
tikv和tidb_tidb优缺点
TiKV 最底层使用的是 RocksDB 做为持久化存储,所以 TiKV 的很多性能相关的参数都是与 RocksDB 相关的。TiKV 使用了两个 RocksDB 实例,默认 RocksDB 实例存储 KV 数据,Raft RocksDB 实例(简称 RaftDB)存储 Raft 数据。
全栈程序员站长
2022/09/29
8960
PD 调度策略最佳实践
众所周知,PD 是整个 TiDB 集群的核心,负责全局元信息的存储以及 TiKV 集群负载均衡调度,本文将详细介绍 PD 调度系统的原理,并通过几个典型场景的分析和处理方式,分享调度策略的最佳实践和调优方法,帮助大家在使用过程中快速定位问题。本文内容基于 3.0 版本,更早的版本(2.x)缺少部分功能的支持,但是基本原理类似,也可以以本文作为参考。
PingCAP
2019/10/12
1.3K0
以TiDB热点问题来谈Region的调度流程
TiDB的核心架构分为TiDB、TiKV、PD三个部分,其中TiKV是一个分布式数据存储引擎用来存储真实的数据,在TiKV中又对存储区域进行了一系列的逻辑划分也就是Region,它是被PD调度的最小单元。熟悉TiDB的读者对这个结构应该了然于胸。
HOHO
2021/08/18
8410
以TiDB热点问题来谈Region的调度流程
TIDB 中的REGION 是如何进行管理和协调的
熟悉TIDB 的同学都知道,TIDB 中的数据库存储节点是TIKV ,而这里TIKV 仅仅是数据的一个“物理”的存储地,并不是一个数据单位,TIKV的数据单元用Region来表达,那么一个TIKV 可以存储多个region,TIKV 和Region之间的关系是什么,之间的性能关系又是什么。
AustinDatabases
2021/10/15
1.1K0
TiKV 源码阅读三部曲(一)重要模块
作者简介:谭新宇,清华大学软件学院研三在读,Apache IoTDB committer,Talent Plan Community mentor。
PingCAP
2022/10/18
9120
TiKV 源码解析系列文章(二)raft-rs proposal 示例情景分析
本文为 TiKV 源码解析系列的第二篇,按照计划首先将为大家介绍 TiKV 依赖的周边库 raft-rs 。raft-rs 是 Raft 算法的 Rust 语言实现。Raft 是分布式领域中应用非常广泛的一种共识算法,相比于此类算法的鼻祖 Paxos,具有更简单、更容易理解和实现的特点。
PingCAP
2019/02/15
7370
TiKV 源码解析系列文章(九)Service 层处理流程解析
之前的 TiKV 源码解析系列文章介绍了 TiKV 依赖的周边库,从本篇文章开始,我们将开始介绍 TiKV 自身的代码。本文重点介绍 TiKV 最外面的一层——Service 层。
PingCAP
2019/07/08
7680
TiKV 源码解析系列文章(十)Snapshot 的发送和接收
TiKV 使用 Raft 算法来提供高可用且具有强一致性的存储服务。在 Raft 中,Snapshot 指的是整个 State Machine 数据的一份快照,大体上有以下这几种情况需要用到 Snapshot:
PingCAP
2019/07/10
8790
TiKV 集群版本的安全迁移
在 TiDB 的产品迭代中,不免会碰到一些兼容性问题出现。通常协议上的兼容性 protobuf 已经能帮我们处理的很好,在进行功能开发,性能优化时,通常会保证版本是向后兼容的,但并不保证向前兼容性,因此,当集群中同时有新旧版本节点存在时,旧版本不能兼容新版本的特性,就有可能造成该节点崩溃,影响集群可用性,甚至丢失数据。目前在有不兼容的版本升级时,会要求进行离线升级,但这会影响到服务,我们需要一个适合的机制来进行不停服务的升级。因此我们需要在进行滚动升级时,让这些不能保证整个集群的向后兼容性的功能不被启用。只有在保证集群中所有节点都已经升级完成后,我们才安全的启用这些功能。
PingCAP
2018/09/22
8600
TIDB TIKV 数据是怎么写入与通过Region 分割的?
国产的分布式数据库不少,TDSQL, OB, TIDB ,等等都是比较知名的产品,使用的分布式协议也不同,有使用POSTGRES-XL ,也有从外观模仿ORACLE 的,还有借鉴各家所长自己研发的。为什么最近一直在看TIDB,主要有以下几点
AustinDatabases
2021/09/24
1.1K0
TIDB  TIKV  数据是怎么写入与通过Region 分割的?
TiKV 源码解析(六)raft-rs 日志复制过程分析
在 《TiKV 源码解析(二)raft-rs proposal 示例情景分析》 中,我们主要介绍了 raft-rs 的基本 API 使用,其中,与应用程序进行交互的主要 API 是:
PingCAP
2019/04/25
7990
推荐阅读
相关推荐
TiKV源码解析系列文章(二十)Region Split源码解析
更多 >
LV.6
这个人很懒,什么都没有留下~
目录
  • channel 声明
  • channel 使用
    • 无缓冲 channel
    • 有缓冲 channel
  • 关闭 channel
  • 单向 channel
  • 实战技巧
    • 控制 goroutine 并发的数量
    • for select 无限循环模式
    • select timeout 模式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档