zoukankan      html  css  js  c++  java
  • [转]Go基础之锁的初识

    当我们的程序就一个线程的时候是不需要用到锁的,但是通常我们实际的代码不会是单个线程的,所有这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢?

    • 当我们多个线程在读相同的数据的时候则是需要加锁的
    • 当我们的程序既有读又有写的时候更是需要加锁的
    • 当我们有多个线程在写的时候同样也是需要加锁

    互斥锁

    互斥锁:同一个时刻只有一个线程能够拿到锁

    我们先通过一个例子来演示,如果当多个线程同时更改一个变量,结果会是怎么样
    不加锁版本

    复制代码
    package main
    
    import (
        "sync"
        "fmt"
    )
    
    var (
        //lock sync.Mutex
        count int
        w sync.WaitGroup  //用于等待子线程执行完之后退出
    )
    
    func main() {
        w.Add(1) // 在调用线程前执行w.add
        go func(){
            for i:=0;i<100000;i++{
                count++
            }
            w.Done()  //执行完 执行w.Done
        }()
        for i :=0;i<100000;i++{
            count++
        }
        w.Wait() // 最后执行w.wait等待所有的线程执行完毕
        fmt.Println(count)
    
    }
    复制代码

    当我们运行多次就可以发现,最后的结果基本不可能是我们先看到的:200000
    我们修改代码代码需要加锁保护的地方加上锁,并且这里加的是互斥锁,修改后的代码为:

    复制代码
    package main
    
    import (
        "sync"
        "fmt"
    )
    
    var (
        lock sync.Mutex
        count int
        w sync.WaitGroup  //用于等待子线程执行完之后退出
    )
    
    func main() {
        w.Add(1) // 在调用线程前执行w.add
        go func(){
            for i:=0;i<100000;i++{
                lock.Lock()
                count++
                lock.Unlock()
            }
            w.Done()  //执行完 执行w.Done
        }()
        for i :=0;i<100000;i++{
            lock.Lock()
            count++
            lock.Unlock()
        }
        w.Wait() // 最后执行w.wait等待所有的线程执行完毕
        fmt.Println(count)
    
    }
    复制代码

    这次当我们多次运行的时候,就能保证我们每次都能看到我们想要的值:200000
    接下来看读写锁

    读写锁

    读写锁主要用到读多写少的场景
    读写锁分为:读锁和写锁

    如果自己设置了一个写锁,那么其他读的线程以及写的线程都拿不到锁,这个时候和互斥锁的功能相同
    如果自己设置了一个读锁,那么其他写的线程是拿不到锁的,但是其他读的线程都是可以拿到这个锁

    我们把上面的例子代码进行更改:

    复制代码
    package main
    
    import (
        "sync"
        "fmt"
    )    
    
    var (
        rwlock sync.RWMutex
        w sync.WaitGroup
        count int
    )
    
    
    func main() {
        w.Add(1)
        go func(){
            for i:=0;i<1000000;i++{
                rwlock.Lock() // 这里定义了一个写锁
                count++
                rwlock.Unlock()
            }
            w.Done()
        }()
    
        for i:=0;i<1000000;i++{
            rwlock.Lock() // 这里定义了一个写锁
            count++
            rwlock.Unlock()
        }
        w.Wait()
        fmt.Println(count)
    }
    复制代码

    通过设置写锁,我们同样可以实现数据的一致性
    下面是一个读锁的使用例子:

    复制代码
    package main
    
    import (
        "sync"
        "fmt"
    )
    
    var (
        rwlock sync.RWMutex
        w sync.WaitGroup
        count int
    )
    
    
    func main() {
        w.Add(1)
        go func(){
            for i:=0;i<1000000;i++{
                rwlock.Lock() // 这里定义了一个写锁
                count++
                rwlock.Unlock()
            }
            w.Done()
        }()
    
        for i:=0;i<16;i++{
            w.Add(1)
            go func(){
                rwlock.RLock() //这里定义了一个读锁
                fmt.Println(count)
                rwlock.RUnlock() //释放读锁
                w.Done()
            }()
        }
        w.Wait()
        fmt.Println(count)
    }
    复制代码

    Go中的原子操作

    原子操作,我们则不需加锁,也能保证数据的一致性
    并且如果只是计算,那么原子操作则是最快的

    实例代码:

    复制代码
    package main
    
    import (
        "sync"
        //"time"
        "sync/atomic"
        "fmt"
    )
    
    var (
        w sync.WaitGroup
        count int32
    )
    
    
    func main() {
        w.Add(1)
        //start := time.Now().UnixNano()
        go func() {
            for i:=0;i<1000000;i++{
                atomic.AddInt32(&count,1)
            }
            w.Done()
        }()
    
        for i:=0;i<1000000;i++{
            atomic.AddInt32(&count,1)
        }
        w.Wait()
        //end := time.Now().UnixNano()
        //fmt.Println((end- start)/1000/1000)
        fmt.Println(count)
    }
    复制代码
    所有的努力都值得期许,每一份梦想都应该灌溉!
  • 相关阅读:
    数据库pubs
    当前目录中查找特定类型的文件
    DBHelper,ADO直接操作数据库,扩展DataTable操作数据裤的方法
    行记录次序+等差数列
    面试的通用要求
    zoj_3367Connect them
    hdoj_4198Quick out of the Harbour
    Win32常见异常
    hdoj_1026Ignatius and the Princess I
    移动 II
  • 原文地址:https://www.cnblogs.com/oxspirt/p/8646703.html
Copyright © 2011-2022 走看看