goroutine之间同步

梦想的初衷 提交于 2020-12-18 06:31:36

一、Go语言中同步的两种方式

同步是一种计算机术语一般指的是在两个或多个数据库、文件、模块、线程之间用来保持数据内容一致性的机制。

并发编程必然要讨论同步,多线程操作同一资源时,如果不能协调好其同步进程,就会出现死锁或数据不一致的问题。举个简单的例子,两个线程同时对变量v(初始值为0)进行加1操作,我们希望两次执行后结果为2,但在并发环境下结果很可能是1。

对于竞争资源的访问就需要同步来协调啦。在Go语言中,有两种同步方式,其一是sync包提供同步操作,调用sync.WaitGroup阻塞所有goroutine直到goroutine执行完毕后才会进入下一步操作,这样就可以让并发操作串行执行。其二是利用channel,各个goroutine共同读写竞争资源转换为共同接收或发送channel,又因为channel自身就可以实现阻塞,从而简化了同步代码。


二、自增ID Server的实现

Don't BB, Show me code. 光说不练假把式,下面我们利用channel实现一个自增ID Server。在各类业务场景中,我们都会遇到为不同的请求分配自增ID,保证各个并发请求获得的ID都是唯一不重复的。这个其实就是多并发访问一个共享变量取值就是的过程,在任一时刻,只允许一个goroutine访问该变量,因此只需要一个容量为1的channel即可解决。

var ch = make(chan struct{}, 1)

func send_channel(){
ch<- struct {}{}
}

func increateIDWithFile(configTypePrefix string) (id string, err error){
<- ch
defer send_channel()
b, err := ioutil.ReadFile(configTypePrefix)
if err != nil {
return "", errors.New("ConfigTypePrefix FIle Read Error")
}
currentCountStr := string(b)

currentCount, err := strconv.ParseInt(currentCountStr, 10, 64)
if err != nil {
return "", errors.New("ConfigType Current Value is illegal")
}

currentCount ++
currentCountStr = strconv.FormatInt(currentCount, 10)

err = ioutil.WriteFile(configTypePrefix, []byte(currentCountStr), 0644)
if err != nil {
return "", errors.New("ConfigTypePrefix File Write Error")
}
configTypePrefix = configTypePrefix+"000000000"
  splitLen := len(configTypePrefix) - len(currentCountStr)
return configTypePrefix[:splitLen]+currentCountStr, nil

}

猜一猜,为什么要把变量写在文件中呢?原因很简单,server关停后后内存中的变量会被清除,为了服务重启后请求获得的ID是正确的,必须数据持久化。





本文分享自微信公众号 - DevOps技术说(sli4book)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!