千家信息网

Go语言互斥锁与读写锁实例分析

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇"Go语言互斥锁与读写锁实例分析"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"G
千家信息网最后更新 2025年01月19日Go语言互斥锁与读写锁实例分析

这篇"Go语言互斥锁与读写锁实例分析"文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇"Go语言互斥锁与读写锁实例分析"文章吧。

    前言:

    单个线程时数据操作的只有一个线程,数据的修改也只有一个线程参与,数据相对来说是安全的,多线程时对数据操作的不止一个线程,所以同时对数据进行修改的时候难免紊乱

    一、互斥锁是什么?

    1.概念

    互斥锁是为了并发的安全,在多个goroutine共同工作的时候,对于共享的数据十分不安全写入时容易因为竞争造成数据不必要的丢失。互斥锁一般加在共享数据修改的地方。

    2.未加锁

    • 线程不安全,操作的全局变量会计算异常

    package mainimport (    "fmt"    "sync")var x int = 0var wg sync.WaitGroupfunc add() {    defer wg.Done()    for i := 0; i < 5000; i++ {        x++    }}func main() {    wg.Add(2)    go add()    go add()    wg.Wait()    fmt.Println(x)}/*打印结果:(每次打印不一样,正常的结果应该是10000)    6051    5059    5748    10000*/

    3.加锁之后

    • 线程安全,全局变量计算无异常

    package mainimport (    "fmt"    "sync")var x int = 0var wg sync.WaitGroup// 创建一个锁对象var lock sync.Mutexfunc add() {    defer wg.Done()    for i := 0; i < 5000; i++ {        //加锁        lock.Lock()        x++        //解锁        lock.Unlock()    }}func main() {    wg.Add(2)    //开启两个线程    go add()    go add()    wg.Wait()    fmt.Println(x)}/*打印结果:    全为10000*/

    二、读写锁【效率革命】

    1.为什么读写锁效率高

    使用锁的时候,安全与效率往往需要互相转换,对数据进行操作的时候,只会进行数据的读与写。 而读与读之间可以同时进行,读与写之间需要保证写的时候不去读。此时为了提高效率就发明读写锁,在读写锁机制下,安全没有丝毫降低,但效率进行了成倍的提升提升的效率在读与写操作次数差异越大时越明显

    2.使用方法

    代码如下(示例):

    package mainimport (    "fmt"    "sync"    "time")var (    x      = 0    rwlock sync.RWMutex    wg     sync.WaitGroup)func write() {    defer wg.Done()    rwlock.Lock()    x++    rwlock.Unlock()}func read() {    wg.Done()    //开启读锁    rwlock.RLock()    fmt.Println(x)    //释放读锁    rwlock.RUnlock()}func main() {    start := time.Now()    for i := 0; i < 100; i++ {        wg.Add(1)        go write()    }    // time.Sleep(time.Second)    for i := 0; i < 10000; i++ {        wg.Add(1)        go read()    }    wg.Wait()    fmt.Println(time.Now().Sub(start))}

    三、sync.once

    1.sync.once产生背景

    在多个goroutine中往往会由于线程不同步造成数据读写的冲突,特别是在进行文件打开对象创建的时候,可能会造成向关闭的文件写内容,使用未初始化的对象,或者对一个对象进行多次初始化。

    2.sync.once机制概述

    sync.once保证函数内的代码只执行一次, 实现的机制是在once内部有一个标志位,在执行代码的时候执行一次之后标志位将置为1后续判断标志位,如果标志位被改为1则无法再进行操纵

    3.sync.once注意点

    sync.Once.Do()传进去的函数参数无参无返,一个once对象只能执行一次Do方法,向Do方法内传多个不同的函数时只能执行第一个传进去的,传进去Do方法的函数无参无返,可以用函数闭包把需要的变量传进去

    4.使用方法

    • 一般结合并发使用,旨在对通道或文件只进行一次关闭

    func f2(a <-chan int, b chan<- int) {    for {        x, ok := <-a        if !ok {            break        }        fmt.Println(x)        b <- x * 10    }    // 确保b通道只关闭一次    once.Do(func() {        close(b)    })}

    四、atomic原子包操作

    原子包将指定的数据进行安全的加减交换操作; 网上还有一大堆关于原子包的api感兴趣的小伙伴可以自行百度,这里就不细细阐述了

    package mainimport (    "fmt"    "sync"    "sync/atomic")var x int64 = 0var wg sync.WaitGroup/*    原子操作是将数据进行打包枷锁,直接通过指定的函数进行相应的操作    可以使用load读取、store写入、add修改、swap交换。    // 类似于读取一个变量、对一个变量进行赋值*/func addone() {    // 没有加锁进行并发的话,会产生数据丢失的情况    defer wg.Done()    // x++    // 不用加锁也可以使用的行云流水    // 第一个参数是进行操作的数据,第二个是增加的步长    atomic.AddInt64(&x, 1)}func csf() {    // 进行比较相等则将新值替换旧值    ok := atomic.CompareAndSwapInt64(&x, 100, 200)    fmt.Println(ok, x)}func main() {    for i := 0; i < 50000; i++ {        wg.Add(1)        go addone()    }    wg.Wait()    fmt.Println(x)    x = 100    csf()    fmt.Println(123)}

    以上就是关于"Go语言互斥锁与读写锁实例分析"这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注行业资讯频道。

    数据 线程 安全 时候 内容 函数 效率 变量 对象 方法 原子 标志 实例 实例分析 语言 分析 代码 多个 文件 机制 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 GEO数据库的p值什么意思 山东春季高考网络技术专业可以报考的学校 四川正规软件开发哪家专业 网络安全讲座的感受 如何把网上的数据库弄下来 江苏互联网络技术服务 广西凭祥网络安全宣传 网络技术阴暗面 阳江自主可控软件开发销售厂 图书数据库都有哪些 数据库手动设置主键外键 服务器 实现版本管理系统 河南炽天使网络技术租号 清晰度数据库 华为服务器怎么直接连接 西安互动网络技术有限公司 魔兽世界服务器地理位置 个人服务器主机出租 什么是数据库安全的地道保障 数据库中如何增加id号设为主键 学校的网络安全性是什么名字 以行为为中心的网络安全保护 端木蕻良小说软件开发 智能化软件开发价格信息 二维晶体结构数据库 动漫的服务器是什么样子的 数据库用哪种软件编写好 武汉市网络安全大会 高并发 数据库安全 存储服务器属于什么税收类别
    0