使用golang的channel的坑


声明:本文转载自https://my.oschina.net/u/553243/blog/1538634,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

很多时候我们经过使用有缓冲channel作为通信控制的功能,以至有一些误解和坑出现。

误解一:有缓存channel是顺序的

执行下面代码。

package main  import (     "time"     "math/rand" )  func main(){     cache:=make(chan int,4)     go func() {         for i:=0;i< 10;i++ {             cache<-i         }     }()     go getCache(cache)     go getCache(cache)     go getCache(cache)     time.Sleep(3*time.Second) }  func getCache(cache <-chan int)  {     for  {         select {         case i:=<-cache:             println(i)             time.Sleep(time.Duration(rand.Int31n(100))*time.Millisecond)         }     }  } 

多执行几次看看结果,并不是每一次都是可以顺序输出的,有缓存channel是乱序的。

误解二:channel缓存的大小就是并发度

如下代码。

package main  import ( 	"fmt" 	"sync" 	"time" )  var wg = sync.WaitGroup{}  func main() { 	wg.Add(2) 	bf := make(chan string, 64) 	go insert(bf) 	go get(bf) 	wg.Wait() } func insert(bf chan string) { 	str := "CockroachDB 的技术选型比较激进,比如依赖了 HLC 来做事务的时间戳。但是在 Spanner 的事务模型的 Commit Wait 阶段等待时间的选择,CockroachDB 并没有办法做到 10ms 内的延迟;CockroachDB 的 Commit Wait 需要用户自己指定,但是谁能拍胸脯说 NTP 的时钟误差在多少毫秒内?我个人认为在处理跨洲际机房时钟同步的问题上,基本只有硬件时钟一种办法。HLC 是没办法解决的。另外 Cockroach 采用了 gossip 来同步节点信息,当集群变得比较大的时候,gossip 心跳会是一个非常大的开销。当然 CockroachDB 的这些技术选择带来的优势就是非常好的易用性,所有逻辑都在一个 binary 中,开箱即用,这个是非常大的优点。" 	for i := 0; i < 10000000; i++ { 		bf <- fmt.Sprintf("%s%d", str, i) 	} 	wg.Done() }  func sprint(s string) { 	time.Sleep(1000 * time.Millisecond) }  func get(bf chan string) { 	for { 		go func() {  			select { 			case str := <-bf: 				sprint(str) 			case <-time.After(3 * time.Second): 				wg.Done() 			}  		}() 	} } 

很多同学乍一看以为定义了

bf := make(chan string, 64) 

就是说该程序的并发度控制在了64,执行就会发现内存一直在增长。 因为get()函数中启动的goroutine会越来越多,因为get()每读取一个数据,insert()就会往channel插入一条数据,此时并发度就不是64了。 需要修改为:

package main  import ( 	"fmt" 	"sync" 	"time" )  var wg = sync.WaitGroup{}  func main() { 	wg.Add(2) 	bf := make(chan string, 64) 	go insert(bf) 	//go get(bf)     for i:=0;i<64;i++ {         go get1(bf)     }  	wg.Wait() } func insert(bf chan string) { 	str := "CockroachDB 的技术选型比较激进,比如依赖了 HLC 来做事务的时间戳。但是在 Spanner 的事务模型的 Commit Wait 阶段等待时间的选择,CockroachDB 并没有办法做到 10ms 内的延迟;CockroachDB 的 Commit Wait 需要用户自己指定,但是谁能拍胸脯说 NTP 的时钟误差在多少毫秒内?我个人认为在处理跨洲际机房时钟同步的问题上,基本只有硬件时钟一种办法。HLC 是没办法解决的。另外 Cockroach 采用了 gossip 来同步节点信息,当集群变得比较大的时候,gossip 心跳会是一个非常大的开销。当然 CockroachDB 的这些技术选择带来的优势就是非常好的易用性,所有逻辑都在一个 binary 中,开箱即用,这个是非常大的优点。" 	for i := 0; i < 10000000; i++ { 		bf <- fmt.Sprintf("%s%d", str, i) 	} 	wg.Done() }  func sprint(s string) { 	time.Sleep(1000 * time.Millisecond) }  func get1(bf chan string)  {     for {         select {         case str := <-bf:             sprint(str)         case <-time.After(3 * time.Second):             wg.Done()         }     } } 

本文发表于2017年09月18日 08:47
(c)注:本文转载自https://my.oschina.net/u/553243/blog/1538634,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2074 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1