Skip to content

多线程编程

本文档介绍Go语言中的多线程编程技术,包括Goroutine管理、同步机制、并发安全等实践方法。

📋 目录

Goroutine管理

在Go语言中,Goroutine是轻量级的并发执行单元,由Go运行时管理。以下是管理Goroutine的常用方法:

启动Goroutine

1. 使用go关键字启动函数

go
package main

import (
    "fmt"
    "time"
)

func someFunction(name string) {
    for i := 0; i < 3; i++ {
        fmt.Printf("%s: %d\n", name, i)
        time.Sleep(100 * time.Millisecond)
    }
}

func main() {
    go someFunction("goroutine-1")  // 启动新的goroutine
    go someFunction("goroutine-2")  // 启动另一个goroutine
    
    someFunction("main")  // 主goroutine执行
    
    // 等待其他goroutine完成
    time.Sleep(time.Second)
}

2. 使用匿名函数创建Goroutine

go
func main() {
    // 匿名函数goroutine
    go func() {
        fmt.Println("匿名函数goroutine执行")
    }()
    
    // 带参数的匿名函数goroutine
    go func(msg string) {
        fmt.Printf("消息: %s\n", msg)
    }("Hello from goroutine")
    
    time.Sleep(time.Second)
}

3. 闭包Goroutine

go
func closureExample() {
    messages := []string{"Hello", "World", "Go"}
    
    for i, msg := range messages {
        // 正确的闭包使用方式
        go func(index int, message string) {
            fmt.Printf("Index: %d, Message: %s\n", index, message)
        }(i, msg)
        
        // 错误的闭包使用(会产生竞态条件)
        // go func() {
        //     fmt.Printf("Index: %d, Message: %s\n", i, msg)
        // }()
    }
    
    time.Sleep(time.Second)
}

Channel通信

使用Channel在Goroutine之间进行安全的数据传输和同步:

1. 基本Channel操作

go
func basicChannelExample() {
    ch := make(chan int)  // 创建无缓冲通道
    
    go func() {
        ch <- 42  // 发送数据到通道
        fmt.Println("数据已发送")
    }()
    
    value := <-ch  // 从通道接收数据
    fmt.Printf("接收到的值: %d\n", value)
}

2. 缓冲Channel

go
func bufferedChannelExample() {
    ch := make(chan string, 3)  // 创建缓冲通道,容量为3
    
    // 发送数据(不会阻塞,因为有缓冲)
    ch <- "message 1"
    ch <- "message 2"
    ch <- "message 3"
    
    // 接收数据
    for i := 0; i < 3; i++ {
        msg := <-ch
        fmt.Printf("接收到: %s\n", msg)
    }
}

3. 双向通信

go
func bidirectionalCommunication() {
    request := make(chan string)
    response := make(chan string)
    
    // 工作goroutine
    go func() {
        for {
            req := <-request
            if req == "quit" {
                break
            }
            response <- fmt.Sprintf("处理了: %s", req)
        }
    }()
    
    // 发送请求
    request <- "任务1"
    fmt.Println(<-response)
    
    request <- "任务2"
    fmt.Println(<-response)
    
    request <- "quit"
}

同步机制

sync.WaitGroup

WaitGroup用于等待一组Goroutine完成:

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

func waitGroupExample() {
    var wg sync.WaitGroup
    
    // 启动3个goroutine
    for i := 1; i <= 3; i++ {
        wg.Add(1)  // 增加等待计数
        
        go func(id int) {
            defer wg.Done()  // 完成时减少计数
            
            fmt.Printf("Goroutine %d 开始工作\n", id)
            time.Sleep(time.Duration(id) * time.Second)
            fmt.Printf("Goroutine %d 完成工作\n", id)
        }(i)
    }
    
    wg.Wait()  // 等待所有goroutine完成
    fmt.Println("所有goroutine都已完成")
}

func main() {
    var wg sync.WaitGroup

    wg.Add(1) // 增加等待组的计数器

    go func() {
        defer wg.Done() // 减少等待组的计数器
        // goroutine 执行的代码
    }()

    wg.Wait() // 等待所有 goroutine 完成
}

这些是在 Go 中操作 goroutine 的一些常用方法和技术。goroutine 提供了一种轻量级的并发机制,可以让你在 Go 中更方便地编写并发程序。通过通道和同步原语,可以有效地控制和管理 goroutine 的并发操作。

基于 MIT 许可发布