首页 > 其他分享 >Go sync 包解析与实战

Go sync 包解析与实战

时间:2023-12-28 09:44:37浏览次数:31  
标签:wg WaitGroup fmt sync func Go 解析

在并发世界中,Go语言以其原生的并发特性脱颖而出。Go的sync包提供了基本的同步原语,如互斥锁(sync.Mutex)、等待组(sync.WaitGroup)等,能够帮助开发者在并发环境下编写更安全、更可靠的代码。本文将深入剖析sync包的核心组件,并通过实例演示其在Go并发程序中的实际应用。

从sync.Mutex到sync.RWMutex

在Go中,同步代码运行是通过在临界区加锁来实现的。sync.Mutex是最基本的互斥锁,保证了同一时刻只有一个goroutine能访问共享资源。让我们看一个sync.Mutex的使用示例:

package main

import (
    "fmt"
    "sync"
)

var (
    counter int
    lock    sync.Mutex
)

func main() {
    const grs = 2
    var wg sync.WaitGroup
    wg.Add(grs)

    for i := 0; i < grs; i++ {
        go func() {
            defer wg.Done()
            lock.Lock()
            v := counter
            v++
            counter = v
            lock.Unlock()
        }()
    }

    wg.Wait()
    fmt.Printf("Final Counter: %d\n", counter)
}

在上述代码中,使用sync.Mutex保证了对变量counter的安全访问。

sync.RWMutex提供了读写锁的功能,适用于读多写少的场景。读锁(RLock)可以被多个goroutine同时持有,而写锁(Lock)在同一时间只能被一个goroutine持有。

sync.WaitGroup深度实践

等待一组goroutine执行完毕是并发编程中的常见需求。sync.WaitGroup正是为此而生。以下是一个WaitGroup的示例:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    tasks := []func(){
        func() { fmt.Println("Task 1 completed.") },
        func() { fmt.Println("Task 2 completed.") },
        func() { fmt.Println("Task 3 completed.") },
    }
    for _, task := range tasks {
        wg.Add(1)
        go func(t func()) {
            defer wg.Done()
            t()
        }(task)
    }
    wg.Wait() // 等待所有任务完成
    fmt.Println("All tasks completed.")
}

在这个例子中,我们创建了一个WaitGroup,为每个任务启动了一个goroutine,并在任务结束时调用Done()方法。Wait()方法将阻塞直到所有任务都调用了Done()

一次性操作的并发安全保障

sync.Once确保在全局范围内只执行一次操作。即使在多个goroutine中调用,操作也将只执行一次。这在初始化共享资源时非常有用。看看以下的例子:

package main

import (
    "fmt"
    "sync"
)

var (
    once     sync.Once
    instance *Singleton
)

type Singleton struct{}

func GetSingleton() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            singleton := GetSingleton()
            fmt.Printf("%p\n", singleton)
        }()
    }
    wg.Wait()
}

在这段代码中,无论调用多少次GetSingleton(),都只会创建一个Singleton实例。

为并发而生的键值对

sync.Map是一个为高效率并发而设计的键值存储结构。它无需使用互斥锁即可安全地被多个goroutine访问,非常适用于读多写少的场景。以下是sync.Map的使用实例:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var sm sync.Map
    sm.Store("hello", "world")

    result, ok := sm.Load("hello")
    if ok {
        fmt.Println(result) // 输出: world
    }

    sm.Delete("hello") // 删除键值对
}

在本例中,我们使用Store方法存储了一个键值对,通过Load检索值,并通过Delete方法删除了键值对。

结语

sync包是Go并发编程的基础之一,掌握它可以帮助你写出更加高效和稳定的并发程序。本文通过介绍Mutex、WaitGroup、Once和Map等组件,展示了如何在Go中运用同步原语。每个组件都有适合它的应用场景,理解和选择合适的组件对于解决并发问题至关重要。随着Go语言的不断发展,这一包也在不断地优化,使得并发编程变得更加简单和高效。

标签:wg,WaitGroup,fmt,sync,func,Go,解析
From: https://www.cnblogs.com/cheyunhua/p/17932001.html

相关文章

  • 前端发送请求的时候 Content-Type 内容分类, django后端分别怎么接收
    前端发送请求时,常见的Content-Type内容类型包括:application/x-www-form-urlencoded这是最常见的内容类型,用于发送键值对形式的数据。数据被编码为URL查询字符串格式。Django后端可以通过request.POST来接收这些参数。multipart/form-data通常用于文件上传的表......
  • webpack(模块modules 和 模块解析)
    模块(Modules)每个模块都具备了条理清晰的设计和明确的目的何为webpack模块与 Node.js模块相比,webpack模块能以各种方式表达它们的依赖关系。下面是一些示例:ES2015 import 语句CommonJS require() 语句AMD define 和 require 语句css/sass/less文件中的 @imp......
  • GOF23--23种设计模式(三)
    一.桥接模式Java中的桥接模式(BridgePattern)是一种结构性设计模式,它将抽象部分和实现部分分离,使它们可以独立变化,同时通过桥接对象将它们连接起来。这种模式将抽象与其实现解耦,使得抽象和实现可以独立变化。抽象和它的实现通过一个桥接类进行连接,使得它们可以各自独立地变化。......
  • 深入解析Linux中的echo命令
    在Linux系统中,echo命令是一个非常常见且强大的工具,用于在终端中输出文本或变量。尽管echo命令的使用看似简单,但实际上,它有许多有趣的功能和选项,本文将深入解析Linux中的echo命令,以便更好地理解和利用这一强大工具。基本用法echo命令的基本用法非常简单,只需要在终端中输入echo,紧接......
  • MongoDB 通配符索引 (wildcard index) 的利与弊
    MongoDB支持在单个字段或多个字段上创建索引,以提高查询性能。MongoDB支持灵活的模式,这意味着文档字段名在集合中可能会有所不同。使用通配符索引可支持针对任意或未知字段的查询。·一个集合中可以创建多个通配符索引·通配符索引可以覆盖与集合中其他索引相同的字段·通配符......
  • Golang基础(一)
    粗略了解Golang的核心特性Go语言的特性一、并发编程不同于传统的多进程或多线程,golang的并发执行单元是一种称为goroutine的协程。其在语言级别提供关键字:go——用于启动协程。chan——golang中用于并发的通道,用于协程的通信。select——golang提供的多路复用机制。close......
  • go依赖的版本管理
    在Go语言的项目中,要将依赖升级到最新版本,你可以使用goget命令。以下是一些常用的步骤和命令:更新单个依赖到最新版本:goget-upackage-name这里package-name是你想要更新的依赖包名。这个命令会将指定的依赖更新到最新版本。更新所有依赖到最新版本:goget-u./........
  • 2023最新中级难度Django面试题,包含答案。刷题必备!记录一下。
    好记性不如烂笔头内容来自面试宝典-中级难度Django面试题合集问:请解释Django的ORM是什么,它是如何工作的?Django的ORM(Object-RelationalMapping)是一种用于将数据库操作映射到Python对象上的技术。ORM提供了一种面向对象的方式来处理数据库,允许开发者通过定义模型......
  • 2023最新高级难度Django面试题,包含答案。刷题必备!记录一下。
    好记性不如烂笔头内容来自面试宝典-高级难度Django面试题合集问:请问Django中的序列化是什么,有哪些常见的序列化方式?在Django框架中,序列化(Serialization)是指将Python对象(如模型实例或查询集)转换为适合存储或传输的数据格式的过程。常见的数据格式包括JSON、XML、CSV等。反......
  • Java线程池ThreadPoolExecutor源码解析
    Java线程池ThreadPoolExecutor源码解析1.ThreadPoolExecutor的构造实现以jdk8为准,常说线程池有七大参数,通常而言,有四个参数是比较重要的publicThreadPoolExecutor(intcorePoolSize,intmaximumPoolSize,lon......