广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang全局变量加锁的问题解决
  • 573
分享到

Golang全局变量加锁的问题解决

2024-04-02 19:04:59 573人浏览 独家记忆
摘要

如果全局变量只读取 那自然是不需要加锁的 如果全局变量多进程读,多进程写,那自然是需要加读写锁的 但是如果全局变量只有一个进程写,其他进程读呢? 如果采用COW的方式,写进程只是通过

如果全局变量只读取 那自然是不需要加

如果全局变量多进程读,多进程写,那自然是需要加读写锁的

但是如果全局变量只有一个进程写,其他进程读呢? 如果采用COW的方式,写进程只是通过单次赋值的方式来更新变量,是否就可以不加锁了呢?

就第三种情况而言:

当然我们通过 Go build -race 或者 go run -race 就会出现

WARNING: DATA RACE。 但是出现 data race 就证明一定有问题么?

其实核心点在于这个赋值是否是原子的。也就是说是否存在 p1 = p2 的写入时,指针被临时替换为p3,并在此时goroutine切出的情况。可以想到的一种情况是64字节的指针需要两次mv才能完成全部变量的赋值。那么就有可能在两次mv中间切出,进而出现p3的情况。

之前在stackoverflow 上有个讨论

https://stackoverflow.com/questions/21447463/is-assigning-a-pointer-atomic-in-go

其中高votes的回答是说:

在go中,唯一保证原子性的操作是在 sync.atomic, 所以如果你想确保原子性,可以使用sync.Mutex 或者 sync.atomic 中的原子函数。 但是我不建议 sync.atomic中函数, 因为你不得不在任何使用指针的地方使用他们,这是非常难做到正确使用的。

用mutex 是好的go style - 你可以很方便的定义一个函数返回指针。 比如


import "sync"
var secretPointer *int
var pointerLock sync.Mutex
func CurrentPointer() *int {
    pointerLock.Lock()
    defer pointerLock.Unlock()
    return secretPointer
}
func SetPointer(p *int) {
    pointerLock.Lock()
    secretPointer = p
    pointerLock.Unlock()
}

所以一个ok的go style 应该是使用 sync.Mutex 的。

golang doc也是这么说的。


type T struct {
 msg string
}
var g *T
func setup() {
 t := new(T)
 t.msg = "hello, world"
 g = t
}
func main() {
 go setup()
 for g == nil {
 }
 print(g.msg)
}

Even if main observes g != nil and exits its loop, there is no guarantee that it will observe the initialized value for g.msg.

In all these examples, the solution is the same: use explicit synchronization.

但是当我们用go tool asm看时, 确实只有一个指令 MOVQ。

所以只能说

因为规范没有指定,所以你应该假设它不是原子的。即使它现在是原子的,它也有可能在不违反规范的情况下改变。

总之我们不应该做赋值原子的假设,而应该按照规范,使用sync.Mutex 来做。

补充:Golang对全局变量加锁同步解决资源访问共享问题——使用Go协程来同时并发计算多个数字(1-200)的阶乘

使用互斥锁解决资源共享问题

使用Go协程来同时并发计算多个数字(1-200)的阶乘,然后存储在数组当中


package main 
import (
 "fmt"
 "time"
)
 
var(
 myMap = make(map[int]int, 10)
)
 
func test(n int){
 res:=1
 for i:=1; i<=n; i++{
  res*=i
 }
 myMap[n]=res
}
 
func main(){
 for i:=1; i<=200; i++{
  go test(i)
 }
 
 time.Sleep(time.Second*10) 
 for i,v:=range myMap{
  fmt.Printf("myMap[%d]=%d\n", i, v)
 }
}

代码如下,运行结果如下:但是我们发现其并没有正常计算出各个数字的阶乘来

原因是我们没有对全局变量myMap加锁,导致了资源抢夺的问题,因此我们可以对代码加入互斥锁


package main 
import (
 "fmt"
 "time"
 "sync"
)
 
var(
 myMap = make(map[int]int, 10)
 //声明一个全局互斥锁
 lock sync.Mutex
)
 
func test(n int){
 res:=1
 for i:=1; i<=n; i++{
  res+=i //这里我将阶乘改成求和,防止数据溢出
 }
 //加锁
 lock.Lock()
 myMap[n]=res
 //解锁
 lock.Unlock()
}
 
func main(){
 for i:=1; i<=200; i++{
  go test(i)
 }
 
 time.Sleep(time.Second*10)
 
 for i,v:=range myMap{
  fmt.Printf("myMap[%d]=%d\n", i, v)
 }
}

对资源加了互斥锁之后,多个协程之间的并发问题就得到了解决

但是上述解决方案不太完美,有其缺陷:

(1)主线程在等待所有goroutine全部完成的时间很难确定

(2)如果主线程休眠时间过长,就会加长等待时间,如果等待时间短了,还可能会有goroutine因为主线程的退出而被销毁

(3)通过全局变量加锁同步来实现通讯,也不利于多个协程对全局变量的读写操作

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。如有错误或未考虑完全的地方,望不吝赐教。

您可能感兴趣的文档:

--结束END--

本文标题: Golang全局变量加锁的问题解决

本文链接: https://www.lsjlt.com/news/125420.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Golang全局变量加锁的问题解决
    如果全局变量只读取 那自然是不需要加锁的 如果全局变量多进程读,多进程写,那自然是需要加读写锁的 但是如果全局变量只有一个进程写,其他进程读呢? 如果采用COW的方式,写进程只是通过...
    99+
    2022-11-12
  • 解决golang 关于全局变量的坑
    学习golang不久,在定义全局变量的时候遇见了坑。写个小例子,增强记忆。 错误版本 var p int func main() { p, err := test(4) if...
    99+
    2022-11-12
  • java全局变量赋值问题如何解决
    在Java中,可以使用静态变量来实现全局变量的赋值。静态变量是指在类中使用关键字"static"声明的变量,它属于整个类而不是某个对...
    99+
    2023-08-29
    java
  • java全局变量赋值问题怎么解决
    在Java中,全局变量可以通过以下几种方式进行赋值:1. 在声明全局变量时直接赋值:```javapublic class MyCl...
    99+
    2023-08-16
    java
  • java全局变量多线程问题如何解决
    在Java中,可以使用以下几种方式来解决全局变量多线程问题:1. 使用synchronized关键字:在访问全局变量时,使用sync...
    99+
    2023-08-26
    java
  • Node.js 全局变量无法挂载问题解决分析
    目录分析与解决 Node.js 全局变量无法挂载的问题🎆问题起因😈问题:找不到 env 解释器分析与解决 Node.js 全局变量无法挂载的问题 🎆问题起因 最近在做一个自己的脚手...
    99+
    2023-05-14
    Node.js 变量挂载 Node.js 全局变量无法挂载
  • Node.js全局变量无法挂载问题怎么解决
    这篇文章主要介绍“Node.js全局变量无法挂载问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Node.js全局变量无法挂载问题怎么解决”文章能帮助大家解决问题。分析与解决 Node.j...
    99+
    2023-07-05
  • Golang共享变量如何解决问题
    目录1. 什么是竞态 2. 如何消除竞态 3. Go 提供的并发工具 3.1 互斥锁 3.2 读写互斥锁 3.3 Once 3.4 竞态检测器 4. 小结 在之前的文章中,我们详细说...
    99+
    2022-11-12
  • Golang开发中如何解决共享变量问题
    目录1、什么是竞态2、如何消除竞态3、Go 提供的并发工具3.1 互斥锁3.2 读写互斥锁3.3 Once3.4 竞态检测器4、小结Go 语言中 goroutine + channe...
    99+
    2022-11-12
  • 解析golang中的并发安全和锁问题
    1. 并发安全 package main import ( "fmt" "sync" ) var ( sum int wg sync.Wa...
    99+
    2022-11-12
  • CSS变量的使用问题怎么解决
    这篇文章主要讲解了“CSS变量的使用问题怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS变量的使用问题怎么解决”吧!1. 小心 !importa...
    99+
    2022-10-19
  • 完美解决docx4j变量替换的问题
    目录docx4j变量替换的问题测试代码docx4j版本下面是工具类docx4j变量替换的问题 最近工作上需要自己完成word文档变量替换的问题 把里面的变量给替换成数据库里的值,但...
    99+
    2022-11-13
  • 如何理解函数体内局部变量定义的问题
    这篇文章主要介绍“如何理解函数体内局部变量定义的问题”,在日常操作中,相信很多人在如何理解函数体内局部变量定义的问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解函数...
    99+
    2022-10-19
  • 全局引入vant后使用Toast的问题及解决
    目录全局引入vant后使用Toast问题1.Toast 的使用(官方)2.问题3.解决小程序中引入vant-weapp toast组件踩坑(Toast不显示)全局引入vant后使用T...
    99+
    2022-11-13
  • 详解C语言中return返回函数局部变量的问题
    目录return返回栈区局部变量的指针return返回栈区局部的临时变量return只读数据段和static数据在计算机中,释放空间并不需要将空间中的内容全部置成0或者1,而是只要设...
    99+
    2022-11-12
  • Vue无法访问.env.development定义的变量值问题及解决
    目录Vue无法访问.env.development定义的变量值vue中.env | .env.development | .env.production使用vue-cli-servi...
    99+
    2023-01-10
    Vue无法访问.env.development .env.development .env.development定义变量值
  • Mysql插入中文变为全问号???的问题 解决方法
    1、检查并修改mysql的my.ini的配置文件复制代码 代码如下:default-character-set=utf8 2、建立数据库是要指定字符集复制代码 代码如下:create...
    99+
    2022-11-15
    Mysql 中文 问号
  • javascript使用var声明变量的问题怎么解决
    这篇文章主要介绍了javascript使用var声明变量的问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇javascript使用var声明变量的问题怎么解决文章都会...
    99+
    2022-10-19
  • Java修改Integer变量值遇到的问题及解决
    目录Java 修改Integer变量值我尝试了两种方法去改变Integer的整型值看看源码Integer值比较需要注意的问题原因解决办法Java 修改Integer变量值 对于Int...
    99+
    2022-11-12
  • 如何解决ie6布局网页padding值加倍的问题
    这篇文章主要介绍“如何解决ie6布局网页padding值加倍的问题”,在日常操作中,相信很多人在如何解决ie6布局网页padding值加倍的问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作