golang的锁

2023-08-21 11:22:52 浏览数 (1)

在Go语言中,锁用于同步访问共享资源。Go语言提供了两种类型的锁:互斥锁(mutex)和读写锁(RWMutex)。

  1. 互斥锁(mutex):互斥锁是最基本的锁之一。它通过 Lock() 和 Unlock() 方法来控制对共享资源的并发访问。当一个 goroutine 获取到互斥锁时,其他 goroutine 将被阻塞直到该 goroutine 释放锁为止。互斥锁适合在读写比例不确定的情况下使用。
  2. 读写锁(RWMutex):读写锁是一种更高效的锁,它允许多个 goroutine 同时读取共享资源,但只允许一个 goroutine 写入共享资源。读写锁通过 RLock()、RUnlock()、Lock() 和 Unlock() 等方法来实现。读写锁适合在读操作远多于写操作的情况下使用,可以减少锁的竞争,提高并发性能。

示例代码:

// 使用互斥锁 var mu sync.Mutex

mu.Lock() // 访问共享资源 mu.Unlock()

// 使用读写锁 var rwMu sync.RWMutex

rwMu.RLock() // 读取共享资源 rwMu.RUnlock()

rwMu.Lock() // 写入共享资源 rwMu.Unlock()

以下是一个使用互斥锁的示例,其中有两个 goroutine 竞争访问一个共享变量 count:

代码语言:javascript复制
go复制代码
package main

import (
    "fmt"
    "sync"
)

var (
    count int
    mu    sync.Mutex
    wg    sync.WaitGroup
)

func main() {
    for i := 0; i < 10; i   {
        wg.Add(1)
        go increment()
    }
    wg.Wait()
    fmt.Println("Final count:", count)
}

func increment() {
    mu.Lock()
    defer mu.Unlock()

    count  
    wg.Done()
}

在这个示例中,我们首先定义了一个计数器 count 和一个互斥锁 mu。然后,我们启动了 10 个 goroutine,每个 goroutine 都会调用 increment 函数来增加计数器的值。

在 increment 函数中,我们先获取互斥锁 mu,然后对计数器 count 进行加一操作,最后释放互斥锁。使用 defer 语句来确保在函数退出之前一定会释放锁。

通过互斥锁 mu 的加锁和解锁操作,我们可以保证同一时刻只能有一个 goroutine 访问共享变量 count,从而避免了竞态条件(race condition)的出现。

以下是一个使用读写锁的示例,其中有多个 goroutine 同时访问一个共享变量 data:

代码语言:javascript复制
go复制代码
package main

import (
    "fmt"
    "sync"
)

var (
    data []int
    rwMu sync.RWMutex
    wg   sync.WaitGroup
)

func main() {
    for i := 0; i < 10; i   {
        wg.Add(1)
        if i%2 == 0 {
            go write(i)
        } else {
            go read(i)
        }
    }
    wg.Wait()
}

func read(id int) {
    rwMu.RLock()
    defer rwMu.RUnlock()

    fmt.Printf("Goroutine %d read: %vn", id, data)
    wg.Done()
}

func write(id int) {
    rwMu.Lock()
    defer rwMu.Unlock()

    data = append(data, id)
    fmt.Printf("Goroutine %d write: %vn", id, data)
    wg.Done()
}

在这个示例中,我们首先定义了一个切片 data 和一个读写锁 rwMu。然后,我们启动了 10 个 goroutine,其中偶数编号的 goroutine 调用 write 函数来向 data 切片中写入数据,奇数编号的 goroutine 调用 read 函数来读取 data 切片中的数据。

在 read 函数中,我们先获取读锁 rwMu.RLock(),然后对 data 进行读取操作,最后释放读锁 rwMu.RUnlock()。由于读锁可以被多个 goroutine 同时持有,因此多个 goroutine 可以同时读取数据,不会相互阻塞。

在 write 函数中,我们先获取写锁 rwMu.Lock(),然后对 data 进行写入操作,最后释放写锁 rwMu.Unlock()。由于写锁只能被一个 goroutine 持有,因此多个 goroutine 尝试同时写入数据时会相互阻塞,直到当前持有写锁的 goroutine 释放锁为止。

通过读写锁 rwMu 的读锁和写锁操作,我们可以保证在写操作时不会有其他 goroutine 对 data 进行读或写操作,而在读操作时可以允许多个 goroutine 同时读取 data,从而提高了程序的并发性能。

0 人点赞