返回

GO并发之好用的sync包

后端







## 简介

Go语言中的并发编程是非常重要的一个特性,它允许你编写多线程程序,充分利用多核处理器的计算能力。然而,并发编程也存在一些挑战,比如如何协调多个线程之间的访问共享资源,以及如何避免数据竞争(data race)等问题。

为了解决这些挑战,Go语言提供了sync包,其中包含了许多并发安全的数据结构和函数。这些数据结构和函数可以帮助你编写出正确且高效的并发程序。

## sync包中的数据结构

sync包中提供了多种并发安全的数据结构,包括:

* **sync.Mutex** :互斥锁,用于保护共享资源的访问。
* **sync.RWMutex** :读写互斥锁,允许多个Goroutine同时读取共享资源,但只能有一个Goroutine同时写入共享资源。
* **sync.WaitGroup** :等待组,用于等待一组Goroutine执行完毕。
* **sync.Once** :一次性执行,确保某个操作只执行一次。
* **sync.Map** :并发安全的Map,可以安全地从多个Goroutine并发访问。

## sync包中的函数

sync包还提供了一些并发相关的函数,包括:

* **sync.Pool** :对象池,可以复用对象,减少内存分配和垃圾回收的开销。
* **sync.Cond** :条件变量,用于等待某个条件满足。
* **sync.Notify** :通知变量,用于唤醒等待在条件变量上的Goroutine。

## sync包的使用示例

### 使用sync.Mutex保护共享资源

```go
package main

import (
    "fmt"
    "sync"
)

var (
    mu    sync.Mutex
    count int
)

func increment() {
    mu.Lock()
    count++
    mu.Unlock()
}

func main() {
    for i := 0; i < 1000; i++ {
        go increment()
    }

    // 等待所有Goroutine执行完毕
    time.Sleep(time.Second)

    fmt.Println(count)
}

在这个示例中,我们使用sync.Mutex来保护count变量。count变量是一个共享资源,多个Goroutine并发访问它。如果没有sync.Mutex的保护,count变量可能会被多个Goroutine同时修改,导致数据不一致。

使用sync.WaitGroup等待一组Goroutine执行完毕

package main

import (
    "fmt"
    "sync"
)

var (
    wg sync.WaitGroup
)

func sayHello() {
    defer wg.Done() // 告诉WaitGroup当前Goroutine已经执行完毕
    fmt.Println("Hello, world!")
}

func main() {
    for i := 0; i < 10; i++ {
        wg.Add(1) // 告诉WaitGroup又增加了一个需要等待的Goroutine
        go sayHello()
    }

    // 等待所有Goroutine执行完毕
    wg.Wait()

    fmt.Println("All Goroutines have finished")
}

在这个示例中,我们使用sync.WaitGroup来等待一组Goroutine执行完毕。wg.Add(1)告诉WaitGroup又增加了一个需要等待的Goroutine。wg.Done()告诉WaitGroup当前Goroutine已经执行完毕。wg.Wait()会一直等待,直到所有的Goroutine都执行完毕。

使用sync.Map实现并发安全的Map

package main

import (
    "fmt"
    "sync"
)

var (
    m sync.Map
)

func main() {
    // 设置一个键值对
    m.Store("key", "value")

    // 获取一个键值对
    value, ok := m.Load("key")
    if ok {
        fmt.Println(value)
    }

    // 删除一个键值对
    m.Delete("key")
}

在这个示例中,我们使用sync.Map来实现并发安全的Map。sync.Map可以安全地从多个Goroutine并发访问。m.Store("key", "value")会设置一个键值对。m.Load("key")会获取一个键值对。m.Delete("key")会删除一个键值对。

结语

sync包是Go语言中一个非常重要的包,它提供了许多并发安全的数据结构和函数,用于管理共享数据和同步Goroutine,保证并发程序的正确性和高效性。本文介绍了sync包中常用的数据结构和函数,并通过示例演示了它们的使用。希望本文能帮助你更好地理解和使用sync包。