当前位置: 首页 > news >正文

【Go语言快速上手】第二部分:Go语言进阶之并发编程

文章目录

  • 一、并发编程
    • 1. goroutine:创建和调度 goroutine
    • 2. channel:无缓冲 channel、有缓冲 channel、select 语句
      • 2.1 无缓冲 channel
      • 2.2 有缓冲 channel
      • 2.3 select 语句
    • 3. sync 包:Mutex、RWMutex、WaitGroup 等同步原语
      • 3.1 Mutex:互斥锁
      • 3.2 RWMutex:读写互斥锁
      • 3.3 WaitGroup:等待多个 goroutine 完成

一、并发编程

Go 语言的并发编程是其一大亮点。通过 goroutinechannel,Go 使得并发编程变得简洁且高效。Go 还提供了 sync 包,包含了多种同步原语,帮助开发者在并发程序中处理共享数据和同步问题。

1. goroutine:创建和调度 goroutine

goroutine 是 Go 中最基本的并发单元,可以认为是轻量级的线程。通过 go 关键字可以轻松创建一个新的 goroutine,并发执行指定的函数或方法。

package main

import (
    "fmt"
    "time"
)

// 一个简单的并发任务
func sayHello() {
    time.Sleep(1 * time.Second)
    fmt.Println("Hello from goroutine!")
}

func main() {
    go sayHello() // 创建一个 goroutine
    fmt.Println("Hello from main!")
    time.Sleep(2 * time.Second) // 等待 goroutine 执行完毕
}

在这个示例中,go sayHello() 启动了一个新的 goroutine,并发执行 sayHello 函数。主函数继续执行并打印输出,最后通过 time.Sleep 等待 goroutine 完成。

在这里插入图片描述


2. channel:无缓冲 channel、有缓冲 channel、select 语句

channel 是 Go 语言用于不同 goroutine 之间通信的机制。通过 channel,可以安全地传递数据,避免了数据竞争问题。Go 提供了无缓冲和有缓冲的 channel,以及 select 语句来处理多个 channel 的操作。

2.1 无缓冲 channel

无缓冲 channel 会在发送数据和接收数据时进行同步,确保发送和接收操作相互配合。

package main

import "fmt"

func main() {
    ch := make(chan string) // 创建一个无缓冲 channel

    // 启动 goroutine 发送数据
    go func() {
        ch <- "Hello from goroutine!" // 向 channel 发送数据
    }()

    // 接收数据
    msg := <-ch
    fmt.Println(msg) // 输出: Hello from goroutine!
}

2.2 有缓冲 channel

有缓冲的 channel 可以在发送数据时不必立即等待接收方,直到缓冲区满或接收方取走数据。创建有缓冲 channel 时,可以指定缓冲区的大小。

package main

import "fmt"

func main() {
    ch := make(chan string, 2) // 创建一个缓冲区大小为 2 的 channel

    ch <- "Hello"
    ch <- "World" // 向 channel 发送两个消息

    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

在这个示例中,channel 的缓冲区大小为 2,可以在不立即接收的情况下向 channel 发送两个数据。

2.3 select 语句

select 语句允许你等待多个 channel 操作。它类似于 switch 语句,但用于处理多个 channel 的发送或接收。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- "Message from ch1"
    }()

    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "Message from ch2"
    }()

    // 使用 select 语句监听多个 channel
    select {
    case msg1 := <-ch1:
        fmt.Println("Received:", msg1)
    case msg2 := <-ch2:
        fmt.Println("Received:", msg2)
    }
}

在这个示例中,select 会等待 ch1ch2 中的任一 channel 可用。当第一个 channel 可用时,它会立即执行对应的 case,并停止等待。

在这里插入图片描述


3. sync 包:Mutex、RWMutex、WaitGroup 等同步原语

Go 提供了 sync 包中的多种同步原语,用于处理并发程序中的共享资源访问问题。

3.1 Mutex:互斥锁

Mutex 是最常用的同步原语,它确保同一时刻只有一个 goroutine 可以访问共享资源。通过 LockUnlock 方法来加锁和解锁。

package main

import (
    "fmt"
    "sync"
)

var counter int
var mutex sync.Mutex

func increment() {
    mutex.Lock() // 加锁
    counter++
    mutex.Unlock() // 解锁
}

func main() {
    var wg sync.WaitGroup

    // 启动多个 goroutine 进行并发操作
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            increment()
        }()
    }

    wg.Wait() // 等待所有 goroutine 执行完毕
    fmt.Println("Final counter:", counter)
}

在这个示例中,使用 Mutex 来保证对 counter 的并发访问是安全的。

在这里插入图片描述

3.2 RWMutex:读写互斥锁

RWMutex 是一种读写互斥锁,它允许多个 goroutine 同时读取共享资源,但在写操作时会阻止其他的读写操作。

package main

import (
    "fmt"
    "sync"
)

var counter int
var rwMutex sync.RWMutex

func read() int {
    rwMutex.RLock() // 读锁
    defer rwMutex.RUnlock()
    return counter
}

func write() {
    rwMutex.Lock() // 写锁
    counter++
    rwMutex.Unlock()
}

func main() {
    var wg sync.WaitGroup

    // 启动多个 goroutine 进行读写操作
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            write()
        }()
    }

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            read()
        }()
    }

    wg.Wait()
    fmt.Println("Final counter:", counter)
}

在这个示例中,RWMutex 允许多个 goroutine 同时进行读操作,但在执行写操作时会锁住资源。

3.3 WaitGroup:等待多个 goroutine 完成

WaitGroup 用于等待一组 goroutine 执行完毕。它提供了 AddDoneWait 方法来控制并发流程。

package main

import (
    "fmt"
    "sync"
)

func task(wg *sync.WaitGroup) {
    defer wg.Done() // 执行完毕时调用 Done
    fmt.Println("Task completed")
}

func main() {
    var wg sync.WaitGroup

    // 启动多个 goroutine
    for i := 0; i < 5; i++ {
        wg.Add(1) // 增加等待的 goroutine 数量
        go task(&wg)
    }

    wg.Wait() // 等待所有 goroutine 执行完毕
    fmt.Println("All tasks completed")
}

在这个示例中,WaitGroup 用于等待多个并发任务完成。

相关文章:

  • 新手向:SpringBoot后端查询到数据,前端404?(附联调时各传参方式注解总结-带你一文搞定联调参数)
  • golang panic原理
  • 解锁大数据治理:开启数据驱动的新时代
  • 图片粘贴上传实现
  • python统计项目计划中2个日期之间的工作天数
  • ubuntu上/etc/profile.d/目录的作用
  • 保护大数据的最佳实践方案
  • 深入理解TypeScript中的类型守卫
  • C# 中的 lock用法
  • Spring Bean 生命周期的执行流程
  • ES12 weakRefs的用法和使用场景
  • frameworks 之 Activity添加View
  • Canal 部署binlog 监听
  • 【MySQL】环境变量配置
  • Linux 命令
  • 汽车长期不保养的危害
  • 【鸿蒙Next】鸿蒙应用发布前的准备
  • 泰山派RK3566移植QT,动鼠标时出现屏幕闪烁
  • 微信支付V3平台证书切换成公钥遇到的问题。【无可用的平台证书,请在商户平台-API安全申请使用微信支付公钥】【 Illegal base64 character 2d】
  • 【CCF CSP-J 2023】一元二次方程
  • 校方就退60件演出服道歉:承诺回收服装承担相关费用,已达成和解
  • 研究完蚂蚁搬家,我好像明白了为什么我们总是堵车
  • 两部门预拨4000万元支持山西、广西、陕西做好抗旱救灾工作
  • 马克思主义理论研究教学名师系列访谈|杜玉华:马克思主义是“认识世界”和“改变世界”的思维工具
  • 聚焦各领域顶尖工匠,《上海工匠》第十季于五一播出
  • 李开复出任福耀科技大学理事会理事,助力学校AI战略