golang学习笔记11——Go 语言的并发与同步实现详解

文章目录

引言

在现代软件开发中,并发和同步是非常重要的概念。Go 语言以其简洁高效的并发模型而备受关注。本文将详细介绍 Go 语言中并发与同步的实现方式,并结合代码示例进行深入讲解。

Go 语言的并发模型

1.goroutine

  • Goroutine 是 Go 语言中实现并发的轻量级线程。与传统的线程相比,goroutine 占用的内存更少,创建和切换的开销也更小。
  • 创建 goroutine 非常简单,只需要在函数调用前加上 go 关键字即可。例如:
golang 复制代码
package main

import (
    "fmt"
    "time"
)

func printNumbers() {
    for i := 1; i <= 5; i++ {
        fmt.Println(i)
        time.Sleep(time.Millisecond * 500)
    }
}

func main() {
    go printNumbers()
    fmt.Println("Main function")
    time.Sleep(time.Second * 2)
}

在上面的代码中,printNumbers 函数会在一个新的 goroutine 中执行,而 main 函数会继续执行。这样就实现了并发执行两个任务。

2.channel

  • channel 是用于 goroutine 之间通信的机制。它可以在不同的 goroutine 之间传递数据,实现同步和协调。
  • 创建 channel 可以使用 make 函数。例如:ch := make(chan int) 创建了一个整数类型的 channel。
  • 可以使用 <- 操作符从 channel 中接收数据或向 channel 中发送数据。例如:
golang 复制代码
package main

import (
    "fmt"
)

func sendData(ch chan int) {
    for i := 1; i <= 5; i++ {
        ch <- i
    }
    close(ch)
}

func main() {
    ch := make(chan int)
    go sendData(ch)
    for num := range ch {
        fmt.Println(num)
    }
}

在上面的代码中,sendData 函数会向 channel 中发送数据,而 main 函数会从 channel 中接收数据。当 sendData 函数发送完所有数据后,会关闭 channel。main 函数中的 for range 循环会自动检测 channel 的关闭,并退出循环。

Go 语言的同步机制

1.mutex

  • mutex(互斥锁)是一种用于保护共享资源的同步机制。在 Go 语言中,可以使用 sync.Mutex 类型来实现互斥锁。
  • 使用互斥锁的步骤如下:
    • 创建一个 sync.Mutex 类型的变量。
    • 在需要保护的代码块前,调用 Lock 方法获取锁。
    • 在代码块执行完毕后,调用 Unlock 方法释放锁。
  • 例如:
golang 复制代码
package main

import (
    "fmt"
    "sync"
)

var counter int
var mutex sync.Mutex

func increment() {
    mutex.Lock()
    defer mutex.Unlock()
    counter++
    fmt.Println(counter)
}

func main() {
    for i := 0; i < 5; i++ {
        go increment()
    }
    // 等待所有 goroutine 执行完毕
    time.Sleep(time.Second)
}

在上面的代码中,increment 函数会对共享变量 counter 进行加一操作。为了避免多个 goroutine 同时访问和修改 counter 变量,使用了互斥锁 mutex。在 increment 函数中,首先调用 Lock 方法获取锁,然后对 counter 进行加一操作,最后调用 Unlock 方法释放锁。

2.wait group

  • WaitGroup 是一种用于等待一组 goroutine 执行完毕的同步机制。在 Go 语言中,可以使用 sync.WaitGroup 类型来实现 WaitGroup。
  • 使用 WaitGroup 的步骤如下:
    • 创建一个 sync.WaitGroup 类型的变量。
    • 在每个需要等待的 goroutine 中,调用 Add 方法增加等待的 goroutine 数量。
    • 在 goroutine 执行完毕后,调用 Done 方法减少等待的 goroutine 数量。
    • 在主 goroutine 中,调用 Wait 方法等待所有 goroutine 执行完毕。
  • 例如:
golang 复制代码
package main

import (
    "fmt"
    "sync"
)

func process(wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Println("Processing...")
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go process(&wg)
    }
    wg.Wait()
    fmt.Println("All processes completed.")
}

在上面的代码中,process 函数会模拟一个处理过程。在主 goroutine 中,创建了一个 sync.WaitGroup 类型的变量 wg。然后,在循环中启动了 5 个 goroutine,并在每个 goroutine 中调用 Add 方法增加等待的 goroutine 数量。在每个 goroutine 执行完毕后,会调用 Done 方法减少等待的 goroutine 数量。最后,在主 goroutine 中,调用 Wait 方法等待所有 goroutine 执行完毕。

总结

Go 语言的并发与同步机制使得开发者能够轻松地编写高效的并发程序。通过 goroutine 和 channel,开发者可以实现轻量级的并发编程,提高程序的性能和响应速度。同时,通过 mutex 和 wait group 等同步机制,开发者可以保护共享资源,确保程序的正确性。在实际开发中,开发者可以根据具体的需求选择合适的并发和同步机制,以实现高效、可靠的程序。

关注我看更多有意思的文章哦!👉👉

相关推荐
_Kayo_4 分钟前
node.js 学习笔记3 HTTP
笔记·学习
uzong2 小时前
技术故障复盘模版
后端
GetcharZp2 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程2 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研3 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi3 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
CCCC13101633 小时前
嵌入式学习(day 28)线程
jvm·学习
apocelipes4 小时前
下划线字段在golang结构体中的应用
golang
星星火柴9364 小时前
关于“双指针法“的总结
数据结构·c++·笔记·学习·算法
小狗爱吃黄桃罐头4 小时前
正点原子【第四期】Linux之驱动开发篇学习笔记-1.1 Linux驱动开发与裸机开发的区别
linux·驱动开发·学习