解析golang中的并发安全和锁问题

 更新时间:2021年11月08日 14:42:21   作者:专职  
本文我们来学习一下golang中的并发安全和锁问题,文章通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

1. 并发安全

package main
 
import (
    "fmt"
    "sync"
)
 
var (
    sum int
    wg sync.WaitGroup
)
 
func test() {
    for i := 0; i < 5000000; i++ {
        sum += 1
    }
    wg.Done()
}
 
func main() {
    // 并发和安全锁
    wg.Add(2)
    go test()
    go test()
 
    wg.Wait()
    fmt.Println(sum)
 
}

  上面的代码中我们开启了两个goroutine去累加变量x的值,这两个goroutine在访问和修改x变量的时候就会存在数据竞争,导致最后的结果与期待的不符。

2. 互斥锁

package main
 
import (
    "fmt"
    "sync"
)
 
var (
    sum int
    wg sync.WaitGroup
    mu sync.Mutex  // 定义一个互斥锁
)
 
func test() {
    for i := 0; i < 10000000; i++ {
        // 互斥锁它能够保证同时只能有一个goroutine去访问共享资源
        mu.Lock()
        sum += 1
        mu.Unlock()
    }
    wg.Done()
}
 
func main() {
    fmt.Println(mu)
    // 并发和安全锁
    wg.Add(2)
    go test()
    go test()
 
    wg.Wait()
    fmt.Println(sum)
 
}

  使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待锁;当互斥锁释放后,等待的goroutine才可以获取锁进入临界区,多个goroutine同时等待一个锁时,唤醒的策略是随机的。

3. 读写互斥锁

互斥锁是完全互斥的,但是有很多实际的场景下是读多写少的,当我们并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。

读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。

package main
 
import (
    "fmt"
    "sync"
    "time"
)
 
var (
    x int
    wg sync.WaitGroup
    mu sync.Mutex  // 定义一个互斥锁
    rw sync.RWMutex  // 定义一个读写锁,注意:只有读多写少的时候,读写锁才能发挥其优势
)
 
func write() {
    rw.Lock()
    x += 1
    time.Sleep(10 * time.Millisecond)  // 假设写入时间耗费10毫秒
    rw.Unlock()
    wg.Done()
}
func read() {
    rw.RLock()
    time.Sleep(time.Millisecond)
    rw.RUnlock()
    wg.Done()
}
 
func main() {
    start := time.Now()
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go write()
    }  // 写耗时:160毫秒左右
 
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go read()
    }  // 读耗时:15毫秒左右
 
    wg.Wait()
    end := time.Now()
    fmt.Println("执行时间:", end.Sub(start))
}

  需要注意的是读写锁非常适合读多写少的场景,如果读和写的操作差别不大,读写锁的优势就发挥不出来。

到此这篇关于golang中的并发安全和锁的文章就介绍到这了,更多相关golang并发和锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文让你理解go语言的Context

    一文让你理解go语言的Context

    在Go语言中,Context(上下文)是一个类型,用于在程序中传递请求范围的值、截止时间、取消信号和其他与请求相关的上下文信息,它在多个goroutine之间传递这些值,使得并发编程更加可靠和简单,本文详细介绍go语言的Context,需要的朋友可以参考下
    2023-05-05
  • Golang中的godoc使用简介(推荐)

    Golang中的godoc使用简介(推荐)

    Godoc是go语言的文档化工具,类似于文档化工具godoc,类似于Python的Docstring和Java的Javadoc,这篇文章主要介绍了Golang中的godoc使用简介,需要的朋友可以参考下
    2022-10-10
  • Go语言深度拷贝工具deepcopy的使用教程

    Go语言深度拷贝工具deepcopy的使用教程

    今天给大家推荐的工具是deepcopy,一个可以对指针、接口、切片、结构体、Map都能进行深拷贝的工具,感兴趣的小伙伴快跟随小编一起学习学习
    2022-09-09
  • 详解Go语言中配置文件使用与日志配置

    详解Go语言中配置文件使用与日志配置

    这篇文章主要为大家详细讲解一下Go语言中调整项目目录结构、增加配置文件使用和增加日志配置的方法,文中示例代码讲解详细,需要的可以参考一下
    2022-06-06
  • 解决goxorm无法更新值为默认值的问题

    解决goxorm无法更新值为默认值的问题

    这篇文章主要介绍了解决goxorm无法更新值为默认值的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Golang使用WebSocket通信的实现

    Golang使用WebSocket通信的实现

    这篇文章主要介绍了Golang使用WebSocket通信的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • GO语言实现批量压缩图片和水印

    GO语言实现批量压缩图片和水印

    这篇文章主要介绍了GO语言实现批量压缩图片和水印,主要用到了github.com/nfnt/resize这个第三方库,仅仅支持JPG图片格式,有相同需求的小伙伴参考下吧。
    2015-03-03
  • Go实现将io.Writer转换成字符串

    Go实现将io.Writer转换成字符串

    golang中提供了各种类型之间的转换方法,其中,将其他类型转换为字符串类型是常见的操作,本文主要介绍了Go实现将io.Writer转换成字符串,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05
  • Golang语言实现gRPC的具体使用

    Golang语言实现gRPC的具体使用

    本文主要介绍了Golang语言实现gRPC的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • k8s容器互联flannel vxlan通信原理

    k8s容器互联flannel vxlan通信原理

    这篇文章主要为大家介绍了k8s容器互联flannel vxlan通信原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04

最新评论