go语言多线程

举报
福州司马懿 发表于 2025/05/26 16:04:01 2025/05/26
【摘要】 Go语言通过Goroutine和Channel实现了高效的多线程编程模型。与传统的操作系统线程不同,Go的并发模型基于用户态线程(Goroutine),由Go运行时(runtime)调度,具有轻量级、高效的特点。以下是Go语言多线程编程的核心概念和示例: 1. Goroutine(协程)Goroutine是Go语言中的轻量级线程(协程),由Go运行时管理,而非操作系统线程。其特点包括:内存占...

Go语言通过GoroutineChannel实现了高效的多线程编程模型。与传统的操作系统线程不同,Go的并发模型基于用户态线程(Goroutine),由Go运行时(runtime)调度,具有轻量级、高效的特点。以下是Go语言多线程编程的核心概念和示例:


1. Goroutine(协程)

Goroutine是Go语言中的轻量级线程(协程),由Go运行时管理,而非操作系统线程。其特点包括:

  • 内存占用小:初始栈约2KB,可动态扩展。
  • 调度高效:Go运行时使用M:N调度模型(多个Goroutine映射到少量OS线程)。
  • 创建简单:通过go关键字即可启动。

示例:启动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("Hello from Main!")
}

2. Channel(通道)

Channel是Go语言中用于Goroutine间通信的机制,基于CSP(Communicating Sequential Processes)模型,提供线程安全的同步方式。

示例:使用Channel通信

package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // 将结果发送到Channel
}

func main() {
    s := []int{1, 2, 3, 4, 5}
    c := make(chan int) // 创建Channel
    
    go sum(s[:len(s)/2], c) // 启动第一个Goroutine
    go sum(s[len(s)/2:], c) // 启动第二个Goroutine
    
    x, y := <-c, <-c // 从Channel接收结果
    fmt.Println(x, y, x+y)
}

3. WaitGroup(等待组)

sync.WaitGroup用于等待一组Goroutine完成后再继续执行主线程。

示例:使用WaitGroup同步

package main

import (
    "fmt"
    "sync"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 通知WaitGroup任务完成
    fmt.Printf("Worker %d starting\n", id)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 3; i++ {
        wg.Add(1) // 增加计数器
        go worker(i, &wg)
    }
    wg.Wait() // 等待所有Goroutine完成
    fmt.Println("All workers done!")
}

4. Mutex(互斥锁)

sync.Mutex用于保护共享资源,避免竞态条件(Race Condition)。

示例:使用Mutex保护共享变量

package main

import (
    "fmt"
    "sync"
)

type Counter struct {
    mu    sync.Mutex
    count int
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

func main() {
    counter := Counter{}
    var wg sync.WaitGroup
    
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Increment()
        }()
    }
    wg.Wait()
    fmt.Println("Final count:", counter.count) // 正确输出1000
}

5. Select(多路复用)

select语句用于同时监听多个Channel的操作,类似网络编程中的epoll

示例:使用Select处理多个Channel

package main

import (
    "fmt"
    "time"
)

func main() {
    c1 := make(chan string)
    c2 := make(chan string)
    
    go func() {
        time.Sleep(1 * time.Second)
        c1 <- "one"
    }()
    
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "two"
    }()
    
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-c1:
            fmt.Println("Received", msg1)
        case msg2 := <-c2:
            fmt.Println("Received", msg2)
        }
    }
}

6. 性能优势

  • 低开销:Goroutine的创建和切换成本远低于OS线程。
  • 高效调度:Go运行时自动将Goroutine映射到OS线程,避免线程频繁切换。
  • 内存高效:Goroutine栈动态增长,适合高并发场景。

7. 注意事项

  1. 避免阻塞主线程:主线程退出会导致所有Goroutine终止。
  2. 防止死锁:确保Channel操作有明确的发送/接收逻辑。
  3. 减少锁竞争:优先使用Channel通信,而非共享内存。

总结

Go语言的多线程模型通过Goroutine和Channel提供了简洁高效的并发编程方式,适用于高并发、分布式系统等场景。结合sync包中的工具(如WaitGroupMutex),开发者可以轻松构建高性能的并发应用。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。