golang wg sync

发布时间:2024-10-02 20:09:24

在Go语言的标准库中,sync包是一个非常重要的模块。它提供了一组用于多线程同步的基本接口和原语。在并发编程中,正确地处理并发访问共享资源是非常重要的。sync包通过提供互斥锁、条件变量等功能,帮助我们实现线程安全的并发程序。

互斥锁

互斥锁是最基本的同步工具之一,可以通过sync.Mutex类型对象实现。互斥锁可以通过Lock()方法获取,通过Unlock()方法释放。在任意时刻只能有一个goroutine持有互斥锁,其他goroutine必须等待互斥锁被释放才能继续执行。这样可以保证共享资源在任何时刻最多只能被一个goroutine访问,避免出现并发访问的问题。

以下是一个简单的示例代码:

import (
    "fmt"
    "sync"
)

func main() {
    var mutex sync.Mutex
    var data int

    go func() {
        mutex.Lock()
        data = 100
        mutex.Unlock()
    }()

    mutex.Lock()
    fmt.Println(data)
    mutex.Unlock()
}

在上面的代码中,我们使用mutex互斥锁来保护共享变量data的读写操作。在main函数中,第一个goroutine使用mutex.Lock()获取互斥锁后,将data设置为100,并通过mutex.Unlock()释放互斥锁。而在main函数中,则是使用mutex.Lock()获取互斥锁后,打印出data的值,并通过mutex.Unlock()释放互斥锁。这样就保证了共享变量data在任意时刻只有一个goroutine在访问。

条件变量

除了互斥锁,sync包还提供了条件变量的实现,用于goroutine之间的等待和唤醒。条件变量可以通过sync.Cond类型对象实现。它与互斥锁配合使用,典型的使用场景是一个或多个goroutine需要等待某个条件满足后才能继续执行。

以下是一个简单的示例代码:

import (
    "fmt"
    "sync"
)

var cond = sync.NewCond(&sync.Mutex{})
var ready bool

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        cond.L.Lock()
        for !ready {
            cond.Wait()
        }
        fmt.Println("goroutine 1: ready")
        cond.L.Unlock()
        wg.Done()
    }()

    cond.L.Lock()
    ready = true
    cond.Signal()
    cond.L.Unlock()

    wg.Wait()
}

在上面的代码中,我们使用cond条件变量和互斥锁cond.L来实现一个等待/通知的模式。在main函数中,我们首先创建了一个WaitGroup对象wg,然后使用wg.Add(1)来增加等待的goroutine数量,以便在所有goroutine执行完毕后等待一段时间。接着我们使用cond.L.Lock()获取互斥锁,并设置ready变量为true,然后通过cond.Signal()方法发出信号唤醒正在等待的goroutine。最后使用完互斥锁后,通过cond.L.Unlock()释放互斥锁。

在另外一个goroutine中,我们使用cond.L.Lock()获取互斥锁,然后通过for循环等待条件ready为true。如果条件不满足,则通过cond.Wait()方法将goroutine阻塞并等待被唤醒。当收到cond.Signal()的通知后,goroutine被唤醒并打印出"goroutine 1: ready"。然后使用cond.L.Unlock()释放互斥锁,并通过wg.Done()告知主函数该goroutine已完成执行。

读写锁

sync包还提供了读写锁sync.RWMutex,它比互斥锁更加灵活,允许多个goroutine同时持有读锁进行读操作,而只有一个goroutine持有写锁进行写操作。这样可以提高并发性能。

以下是一个简单的示例代码:

import (
    "fmt"
    "sync"
)

var (
    data   map[string]string
    rwLock sync.RWMutex
)

func main() {
    data = make(map[string]string)
    go func() {
        rwLock.Lock()
        data["key"] = "value"
        rwLock.Unlock()
    }()

    rwLock.RLock()
    fmt.Println(data["key"])
    rwLock.RUnlock()
}

在上面的代码中,我们使用rwLock读写锁来保护共享变量data的读写操作。在一个goroutine中,我们使用rwLock.Lock()获取写锁,然后向data中添加一个键值对,最后通过rwLock.Unlock()释放写锁。而在另外一个goroutine中,我们使用rwLock.RLock()获取读锁,并通过fmt.Println打印出data中指定键的值,然后通过rwLock.RUnlock()释放读锁。

通过使用读写锁,我们可以实现多个goroutine同时读取共享资源的操作,从而提高并发性能。

相关推荐