Skip to content

Goroutine基础

Goroutine是Go语言并发编程的核心,本文档介绍Goroutine的基本概念、特性和使用方法。

📋 目录

什么是Goroutine

Goroutine是Go语言中的轻量级线程,是Go并发编程的基础单元。它可以与其他函数或方法并发执行,实现真正的并行处理。

核心特点

  • 轻量级:创建成本极低,可以轻松创建成千上万个Goroutine
  • 并发执行:多个Goroutine可以同时运行
  • 自动调度:由Go运行时自动管理和调度

Goroutine的优势

与传统线程对比

特性Goroutine传统线程
内存开销2KB起始栈2MB固定栈
创建成本极低较高
切换成本纳秒级微秒级
数量限制数十万个数千个
调度方式协作式调度抢占式调度

技术优势

  1. 动态栈管理

    • 初始栈大小仅2KB
    • 根据需要自动扩展和收缩
    • 避免栈溢出问题
  2. M:N调度模型

    • 多个Goroutine映射到少数OS线程
    • 智能负载均衡
    • 自动处理阻塞操作
  3. 内置通信机制

    • 通过Channel进行安全通信
    • 避免共享内存竞争
    • 遵循"不要通过共享内存来通信,而要通过通信来共享内存"

创建Goroutine

基本语法

在函数调用前加上go关键字即可创建Goroutine:

go
go functionName()  // 创建新的Goroutine执行函数

第一个Goroutine示例

go
package main

import (
    "fmt"
    "time"
)

func hello() {
    fmt.Println("Hello from Goroutine!")
}

func main() {
    go hello()  // 创建新的Goroutine
    fmt.Println("Hello from main!")
    
    // 等待Goroutine执行完成
    time.Sleep(1 * time.Second)
}

输出结果:

Hello from main!
Hello from Goroutine!

Goroutine的特性

1. 非阻塞执行

Goroutine的创建是非阻塞的,程序不会等待Goroutine执行完成:

go
func main() {
    go hello()  // 立即返回,不等待hello()执行完成
    fmt.Println("main function")  // 立即执行
    // 程序可能在hello()执行前就结束了
}
    fmt.Println("main function")
}

上面的程序中,第13行,我们调用 time 包的 Sleep 函数来使调用该函数所在的协程休眠。在这里是让主协程休眠1秒钟。现在调用 go hello() 有了足够的时间得以在主协程退出之前执行。该程序首先打印 Hello world goroutine,等待1秒钟之后打印 main function。

在主协程中使用 Sleep 函数等待其他协程结束的方法是不正规的,我们用在这里只是为了说明Go协程是如何工作的。信道可以用于阻塞主协程,直到其他协程执行完毕。我们将在下一篇教程中讨论信道。

开启多个协程

让我们写一个程序开启多个协程来更好的理解协程。

go
package main
import (  
    "fmt"
    "time"
)
func numbers() {  
    for i := 1; i <= 5; i++ {
        time.Sleep(250 * time.Millisecond)
        fmt.Printf("%d ", i)
    }
}
func alphabets() {  
    for i := 'a'; i <= 'e'; i++ {
        time.Sleep(400 * time.Millisecond)
        fmt.Printf("%c ", i)
    }
}
func main() {  
    go numbers()
    go alphabets()
    time.Sleep(3000 * time.Millisecond)
    fmt.Println("main terminated")
}

上面的程序在第21和22行开启了两个协程。现在这两个协程同时执行。numbers 协程最初睡眠 250 毫秒,然后打印 1,接着再次睡眠然后打印2,以此类推,直到打印到 5。类似地,alphabets 协程打印从 a 到 e 的字母,每个字母之间相隔 400 毫秒。主协程开启 numbers 和 alphabets 协程,等待 3000 毫秒,最后终止。

程序的输出为:

1 a 2 3 b 4 c 5 d e main terminated

下面的图片描述了这个程序是如何工作的,请在新的标签中打开图像以获得更好的效果:

image

上图中,蓝色的线框表示 numbers 协程,栗色的线框表示 alphabets 协程。绿色的线框表示主协程。黑色的线框合并了上述三个协程,向我们展示了该程序的工作原理。每个框顶部的 0ms,250 ms 的字符串表示以毫秒为单位的时间,在每个框底部的 1,2,3 表示输出。

蓝色的线框告诉我们在 250ms 的时候打印了1,在 500ms 的时候打印了2,以此类推。因此最后一个线框底部的输出:1 a 2 3 b 4 c 5 d e main terminated 也是整个程序的输出。上面的图像是很好理解的,您将能够了解该程序的工作原理。

基于 MIT 许可发布