it编程 > 前端脚本 > Golang

Go语言中sync包使用方法教程

4人参与 2025-04-24 Golang

go 语言的 sync 包提供了基本的同步原语,用于在并发编程中协调 goroutine 之间的操作。

1. 互斥锁 (mutex)

互斥锁用于保护共享资源,确保同一时间只有一个 goroutine 可以访问。

特点:

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var mutex sync.mutex
    counter := 0
    
    for i := 0; i < 1000; i++ {
        go func() {
            mutex.lock()
            defer mutex.unlock()
            counter++
        }()
    }
    
    time.sleep(time.second)
    fmt.println("计数器:", counter)
}

2. 读写锁 (rwmutex)

当多个 goroutine 需要读取而很少写入时,读写锁比互斥锁更高效。

特点:

var rwmutex sync.rwmutex
var data map[string]string = make(map[string]string)

// 读取操作
func read(key string) string {
    rwmutex.rlock()
    defer rwmutex.runlock()
    return data[key]
}

// 写入操作
func write(key, value string) {
    rwmutex.lock()
    defer rwmutex.unlock()
    data[key] = value
}

3. 等待组 (waitgroup)

等待组用于等待一组 goroutine 完成执行。

特点:

func main() {
    var wg sync.waitgroup
    
    for i := 0; i < 5; i++ {
        wg.add(1) // 增加计数器
        go func(id int) {
            defer wg.done() // 完成时减少计数器
            fmt.printf("工作 %d 完成\n", id)
        }(i)
    }
    
    wg.wait() // 等待所有 goroutine 完成
    fmt.println("所有工作已完成")
}

4. 一次性执行 (once)

once 确保一个函数只执行一次,无论有多少 goroutine 尝试执行它。

特点:

var once sync.once
var instance *singleton

func getinstance() *singleton {
    once.do(func() {
        instance = &singleton{}
    })
    return instance
}

5. 条件变量 (cond)

条件变量用于等待或宣布事件的发生。

特点:

var mutex sync.mutex
var cond = sync.newcond(&mutex)
var ready bool

func main() {
    go producer()
    
    // 消费者
    mutex.lock()
    for !ready {
        cond.wait() // 等待条件变为真
    }
    fmt.println("数据已准备好")
    mutex.unlock()
}

func producer() {
    time.sleep(time.second) // 模拟工作
    
    mutex.lock()
    ready = true
    cond.signal() // 通知一个等待的 goroutine
    // 或使用 cond.broadcast() 通知所有等待的 goroutine
    mutex.unlock()
}

6. 原子操作 (atomic)

对于简单的计数器或标志,可以使用原子操作包而不是互斥锁。

特点:

import (
    "fmt"
    "sync/atomic"
    "time"
)

func main() {
    var counter int64 = 0
    
    for i := 0; i < 1000; i++ {
        go func() {
            atomic.addint64(&counter, 1)
        }()
    }
    
    time.sleep(time.second)
    fmt.println("计数器:", atomic.loadint64(&counter))
}

7. map (sync.map)

go 1.9 引入的线程安全的 map。

特点:

var m sync.map

func main() {
    // 存储键值对
    m.store("key1", "value1")
    m.store("key2", "value2")
    
    // 获取值
    value, ok := m.load("key1")
    if ok {
        fmt.println("找到键:", value)
    }
    
    // 如果键不存在则存储
    m.loadorstore("key3", "value3")
    
    // 删除键
    m.delete("key2")
    
    // 遍历所有键值对
    m.range(func(key, value interface{}) bool {
        fmt.println(key, ":", value)
        return true // 返回 false 停止遍历
    })
}

8. pool (sync.pool)

对象池用于重用临时对象,减少垃圾回收压力。

特点:

var bufferpool = sync.pool{
    new: func() interface{} {
        return new(bytes.buffer)
    },
}

func process() {
    // 获取缓冲区
    buffer := bufferpool.get().(*bytes.buffer)
    buffer.reset() // 清空以便重用
    
    // 使用缓冲区
    buffer.writestring("hello")
    
    // 操作完成后放回池中
    bufferpool.put(buffer)
}

9. 综合示例

下面是一个综合示例,展示了多个同步原语的使用:

package main

import (
    "fmt"
    "sync"
    "time"
)

type safecounter struct {
    mu sync.mutex
    wg sync.waitgroup
    count int
}

func main() {
    counter := safecounter{}
    
    // 启动 5 个 goroutine 增加计数器
    for i := 0; i < 5; i++ {
        counter.wg.add(1)
        go func(id int) {
            defer counter.wg.done()
            
            for j := 0; j < 10; j++ {
                counter.mu.lock()
                counter.count++
                fmt.printf("goroutine %d: 计数器 = %d\n", id, counter.count)
                counter.mu.unlock()
                
                // 模拟工作
                time.sleep(100 * time.millisecond)
            }
        }(i)
    }
    
    // 等待所有 goroutine 完成
    counter.wg.wait()
    fmt.println("最终计数:", counter.count)
}

最佳实践

总结 

到此这篇关于go语言中sync包使用方法的文章就介绍到这了,更多相关go语言sync包使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

Go语言fmt模块的完整方法详解及示例代码

04-24

GoLand 中设置默认项目文件夹的实现

04-24

Go语言中html/template模块详细功能介绍与示例代码

04-24

GORM中Model和Table的区别及使用

04-24

Go语言标准库中math模块详细功能介绍与示例代码

04-24

gin+gorm实现goweb项目的示例代码

04-24

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论