首页 > 其他分享 >Go 原生 Channel 有这么多坑?应该如何避免?

Go 原生 Channel 有这么多坑?应该如何避免?

时间:2024-01-02 11:33:26浏览次数:30  
标签:原生 ch chan channel func Go 多坑 Channel


Go 原生 Channel 有这么多坑?应该如何避免?_golang

ch := make(chan interface{}, 1024)

func produce(item interface{}) {
    ch <- item
}

func consume() {
    for item := range ch {
        // 异步消费
        go func() {
            _ = item // processing item
        }()
    }
}

Go 原生 Channel 有这么多坑?应该如何避免?_Go_02

Go 原生 Channel 有这么多坑?应该如何避免?_sed_03

Go 原生 Channel 有这么多坑?应该如何避免?_Go_04

Go 原生 Channel 有这么多坑?应该如何避免?_后端_05

Go 原生 Channel 有这么多坑?应该如何避免?_Go_06

仓库地址:https://github.com/bytedance/gopkg

Go 原生 Channel 有这么多坑?应该如何避免?_后端_07

Go 原生 Channel 有这么多坑?应该如何避免?_golang_08

Go 原生 Channel 有这么多坑?应该如何避免?_开发语言_09

var aborted int32
var ch = channel.New(
    channel.WithNonBlock(),
    channel.WithTimeout(time.Second),
    channel.WithTimeoutCallback(func(i interface{}) {
       atomic.AddInt32(&aborted, 1) // monitor timeout task
    }),
)
// 生产速度:每 10ms 生产一条消息
func produce() {
    for i := 1; i <= 20; i++ {
       ch.Input(i)
       time.Sleep(time.Millisecond * 10)
    }
}
// 消费速度:每 100ms 消费一条消息
var consumed int
func consume() {
    for item := range ch.Output() {
        consumed++
        time.Sleep(time.Millisecond * 100) // 例如 RPC 调用
    }
}

Go 原生 Channel 有这么多坑?应该如何避免?_golang_10

Go 原生 Channel 有这么多坑?应该如何避免?_后端_11

var cpuChecker = func() func(c channel.Channel) bool {
   var overloaded int32
   go func() {
      for {
         cpuPercent := cpu.Percent(time.Second) // cost 1 second
         if cp >= 0.5 {
            atomic.CompareAndSwapInt32(&overloaded, 0, 1)
         } else {
            atomic.CompareAndSwapInt32(&overloaded, 1, 0)
         }
      }
   }()
   return func(c channel.Channel) bool {
      return atomic.LoadInt32(&overloaded) > 0
   }
}

var channel = channel.New(
    channel.WithThrottle(cpuChecker()),
)

Go 原生 Channel 有这么多坑?应该如何避免?_开发语言_12

Go 原生 Channel 有这么多坑?应该如何避免?_golang_13

五、FAQ

  1. 是不是用了这个库一定不会有故障?

这个库的目的是尽可能避免传统 channel 会遇到的坑,并帮助你实现更多生产级别的控制能力,至于需要什么样的控制完全取决于使用姿势。

此外,如果系统本身就处于处理能力跟不上的状态,该库更多提供的是快速恢复和丢弃任务的功能,而非也没有能力做到完全无损。

不过它的接口设计也一定程度避免了一些常见的 Go 原生 channel 的坑,比如:允许重复关闭 channel,允许对closed channel 写入。尽可能不 panic。

  1. 是不是要把所有 Go 原生 chan 都换成这个库?

没有必要,在性能上也会有损。不是每一个 channel 都在系统中是核心通信交互的作用。有些可能仅仅只是作为一个信号事件来用。

只有真正有大量生产消费关系的 channel ,需要用该库替换。

  1. 是否需要主动关闭 channel ?

与 Go 原生 chan 结构一样,关闭 channel 并不是必须的。如果你不主动调用 ch.Close() ,该库会在你不持有 ch 引用时,自动关闭 ch。

  1. 为什么 Input 的时候不能使用原生 <- 的语法?

Go chan 的「写入」语法并不能帮助我们实现很多功能性需求,且暴露可写 chan 类型给用户容易产生误用,尤其是容易出现往 closed chan 中写入数据的常见报错。所以目前使用 Input() 函数方式。可扩展性和安全性都要比原始 chan <- value 这种用法要好得多。

  1. 性能比原生 channel 对比如何?

由于引入了中间缓冲层,所以性能上必然是劣于原生 chan 的。但是该库的使用场景更多是功能导向的需求而非性能。

目前压测下,性能比原生要差 3-5 倍。单次操作在 500ns 级别。

  1. 使用上有哪些注意事项?

为了与原生 channel 在语义上尽可能接近,默认依然是有 size 以及阻塞的。如需实现非阻塞 channel,需要手动指定 WithNonBlock option。

标签:原生,ch,chan,channel,func,Go,多坑,Channel
From: https://blog.51cto.com/u_15257216/9065912

相关文章

  • Proximal Policy Optimization (PPO): A Robust and Efficient RL Algorithm
    1.背景介绍ProximalPolicyOptimization(PPO)是一种强化学习(ReinforcementLearning,RL)算法,它在许多实际应用中表现出色,具有较强的鲁棒性和效率。在这篇文章中,我们将详细介绍PPO的核心概念、算法原理、具体实现以及潜在的未来趋势和挑战。1.1强化学习简介强化学习是一种......
  • 前端歌谣-第柒拾叁课-node操作mongodb实现增删改查(图片上传功能)
    前言大家好我是歌谣今天继续给大家带来node操作mongodb实现增删改查实现上传功能环境准备后端mongodb数据库+node前端ejs模板安装处理文件的依赖npmimulter后端启动.\mongod--dbpath.\data\db后台运行连接数据库清空数据前端部分前端目录controller层constUserService=r......
  • 第五章 Going on
    只是一个周末的时间,徐潇却迫不及待了。徐潇只是单纯的想回到学校,在这个新的集体中,徐潇还有好多人不认识。而且,他心里其实也想抓住这次机会,好好发展一下和关昭涵的关系,毕竟机会不是时常有的。抱着这样的想法,徐潇走进了教室。不过,刚进门他就看到了——关昭涵正高兴地和曲文东说着什......
  • codeforces比赛(3):codeforces good_bye_2023
    A、2023跳转原题点击此:A题地址1、题目大意  在一个乘积可能等于2023的数组a中去掉了k个数,得到新的长度为n的b数列。请你输出k个数,使得这k个数与b数列相乘为2023.如果不存在则输出No。2、题目解析  因为这道题的n和k都是不超过5,所以我们只需要算出b数组的乘积是否是2023的......
  • 2023 Goodbye!
    摆了一天,终于想起今天该跨年了(虽然那个时候我可能还在教室里),该写点什么。可是真的打开文档,却发现倏忽而过的2023好像并没有给我留下什么深刻的印象。那就浅浅地用最后三天的生活总结这一年吧。2023.12.31今天推掉了父母约出去和亲戚吃饭的事,一方面作业很多,另一方面一天的假期......
  • Go 语言为什么很少使用数组?
    大家好,我是frank,「Golang语言开发栈」公众号作者。01介绍在Go语言中,数组是一块连续的内存,数组不可以扩容,数组在作为参数传递时,属于值传递。数组的长度和类型共同决定数组的类型,不同类型的数组之间不可以比较,否则在编译时会报错。因为数组的一些特性,我们在Go项目开发中,很少使......
  • CF997E Good Subsegments
    对于这一类析合树问题有简单的线段树扫描线做法:考虑一个长为\(len\)的区间内一定有\(len-1\)个数值相邻的对,于是每次新加一个数\(a_i\)可以考虑相邻的两个数的出现位置\(p\),若\(p\lei\)就对\([1,p]\)区间加,表示左端点在\([1,p]\)的区间内多出一个相邻对接下来的问......
  • MongoDB
    MongoDB的特点:数据分层管理在MySQL里面:1个DBMS(数据库管理系统)可以有很多DB(数据库)1个DB里面可以有很多table(表)1个table里面可以有很多条data(数据)在MongoDB里面:1个DBMS可以有很多DB......
  • 像Google SRE一样OnCall【转载】
    在GoogleSRE的著作《Google运维解密》[1](原作名:SiteReliabilityEngineering:HowGoogleRunsProductionSystems)中,GoogleSRE的关键成员们几乎不惜用了三个章节的篇幅描述了在Google他们是如何OnCall的。GoogleSRE实践中,有一个广为人知的理念:减少琐事,用软件工程......
  • 前端歌谣-第陆拾玖课-MongoDB之node操作实现数据库增删改查
    前言大家好我是歌谣今天给大家带来的是MongoDB关于node操作数据库的讲解依赖配置需要安装express-genetator脚手架创建项目配置文件{"name":"myapp","version":"0.0.0","private":true,"scripts":{"start":"node./bin/w......