Go中的并发模型:Goroutine和Channel
字数 962 2025-11-01 23:47:50

Go中的并发模型:Goroutine和Channel

Go的并发模型基于Goroutine(轻量级线程)和Channel(通道),通过它们可以高效安全地实现并发编程。下面逐步讲解其核心概念和用法。


1. Goroutine:轻量级并发单元

描述
Goroutine是Go语言中的并发执行单元,比操作系统线程更轻量(初始栈约2KB,可动态扩容),由Go运行时调度,而非操作系统内核。

创建与使用

  • 通过go关键字启动一个Goroutine:
    go func() {
        // 并发执行的代码
    }()
    
  • 示例:主线程与Goroutine并行执行
    package main
    import (
        "fmt"
        "time"
    )
    
    func sayHello() {
        fmt.Println("Hello from Goroutine!")
    }
    
    func main() {
        go sayHello() // 启动Goroutine
        time.Sleep(100 * time.Millisecond) // 等待Goroutine执行(临时方案)
        fmt.Println("Main function ends.")
    }
    
    注意:直接使用Sleep等待Goroutine不严谨,实际需用Channel或sync.WaitGroup同步。

2. Channel:Goroutine间的通信机制

描述
Channel是类型安全的管道,用于Goroutine间传递数据和同步操作。遵循“不要通过共享内存通信,而要通过通信共享内存”的原则。

基本用法

  • 创建Channel:
    ch := make(chan int) // 无缓冲Channel
    bufferedCh := make(chan int, 3) // 有缓冲Channel(容量为3)
    
  • 发送与接收数据:
    ch <- 42       // 发送数据到Channel
    value := <-ch  // 从Channel接收数据
    

无缓冲 vs 有缓冲Channel

  • 无缓冲Channel:发送和接收操作会阻塞,直到另一方准备好(同步通信)。
  • 有缓冲Channel:发送方在缓冲区满时阻塞,接收方在缓冲区空时阻塞(异步通信)。

3. 同步示例:使用Channel等待Goroutine结束

package main
import "fmt"

func worker(done chan bool) {
    fmt.Println("Working...")
    done <- true // 发送完成信号
}

func main() {
    done := make(chan bool)
    go worker(done)
    <-done // 阻塞直到收到信号
    fmt.Println("Done.")
}

4. 常见模式:Select多路复用

描述
select语句监听多个Channel操作,处理多个通信任务。

示例

ch1, ch2 := make(chan string), make(chan string)

go func() { ch1 <- "from ch1" }()
go func() { ch2 <- "from ch2" }()

for i := 0; i < 2; i++ {
    select {
    case msg1 := <-ch1:
        fmt.Println(msg1)
    case msg2 := <-ch2:
        fmt.Println(msg2)
    }
}

关键点

  • select会阻塞直到某个Case可执行。
  • 多个Case同时就绪时,随机选择一个执行(避免饥饿)。

5. 避免竞态条件(Race Condition)

问题:多个Goroutine同时修改共享数据可能导致结果不一致。
解决方案

  • 使用Channel传递数据所有权(推荐)。
  • 或使用sync.Mutex加锁:
    var mu sync.Mutex
    var counter int
    
    func safeIncrement() {
        mu.Lock()
        counter++ // 临界区
        mu.Unlock()
    }
    

6. 实践建议

  1. 优先使用Channel:简化同步逻辑,避免显式锁。
  2. 避免Goroutine泄漏:确保每个Goroutine都能退出(如通过context.Context取消)。
  3. 谨慎使用全局变量:尽量通过Channel传递数据。

通过以上步骤,你可以理解Goroutine和Channel如何协作构建高效并发程序。

Go中的并发模型:Goroutine和Channel Go的并发模型基于 Goroutine (轻量级线程)和 Channel (通道),通过它们可以高效安全地实现并发编程。下面逐步讲解其核心概念和用法。 1. Goroutine:轻量级并发单元 描述 : Goroutine是Go语言中的并发执行单元,比操作系统线程更轻量(初始栈约2KB,可动态扩容),由Go运行时调度,而非操作系统内核。 创建与使用 : 通过 go 关键字启动一个Goroutine: 示例:主线程与Goroutine并行执行 注意 :直接使用 Sleep 等待Goroutine不严谨,实际需用Channel或 sync.WaitGroup 同步。 2. Channel:Goroutine间的通信机制 描述 : Channel是类型安全的管道,用于Goroutine间传递数据和同步操作。遵循“不要通过共享内存通信,而要通过通信共享内存”的原则。 基本用法 : 创建Channel: 发送与接收数据: 无缓冲 vs 有缓冲Channel : 无缓冲Channel :发送和接收操作会阻塞,直到另一方准备好(同步通信)。 有缓冲Channel :发送方在缓冲区满时阻塞,接收方在缓冲区空时阻塞(异步通信)。 3. 同步示例:使用Channel等待Goroutine结束 4. 常见模式:Select多路复用 描述 : select 语句监听多个Channel操作,处理多个通信任务。 示例 : 关键点 : select 会阻塞直到某个Case可执行。 多个Case同时就绪时,随机选择一个执行(避免饥饿)。 5. 避免竞态条件(Race Condition) 问题 :多个Goroutine同时修改共享数据可能导致结果不一致。 解决方案 : 使用Channel传递数据所有权(推荐)。 或使用 sync.Mutex 加锁: 6. 实践建议 优先使用Channel :简化同步逻辑,避免显式锁。 避免Goroutine泄漏 :确保每个Goroutine都能退出(如通过 context.Context 取消)。 谨慎使用全局变量 :尽量通过Channel传递数据。 通过以上步骤,你可以理解Goroutine和Channel如何协作构建高效并发程序。