Go 协程(Goroutine)入门与基础使用

发布于:2025-06-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

一、什么是协程(Goroutine)?

简单来说,协程是由 Go 语言运行时管理的轻量级线程。相比系统线程,它的调度开销极小,内存占用非常少(默认只需 2KB 栈空间)。

你可以在一个程序中轻松创建成千上万个 goroutine,而不会像传统线程那样造成系统负担。

二、如何创建一个协程

只需要在函数调用前加上 go 关键字,Go 就会在新的协程中异步执行该函数:

package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Hello from goroutine")
}

func main() {
    go sayHello() // 启动一个新的协程
    time.Sleep(1 * time.Second) // 给协程执行的时间
}

如果不加 time.Sleep主线程可能直接退出,协程还没执行完,即不会输出"Hello from goroutine"。

三、多个协程并发执行

我们可以轻松开启多个任务同时运行:

package main

import (
	"fmt"
	"time"
)

func main() {
	for i := 0; i < 5; i++ {
		go func(i int) {
			fmt.Printf("Worker %d is running\n", i)
		}(i)
	}

	time.Sleep(1 * time.Second)
}

输出顺序是不确定的,因为每个协程的调度是由 Go 运行时决定的。

四、协程与主线程的关系

主函数是 Go 程序的入口,也是主协程。一旦 main() 执行完毕,程序就退出,即使其他协程还在执行

为了解决这个问题,我们常用 sync.WaitGroup 等机制来等待所有协程结束:

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func worker(id int) {
	defer wg.Done()
	fmt.Printf("Worker %d done\n", id)
}

func main() {
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go worker(i)
	}
	wg.Wait() // 等待所有 goroutine 完成
}

五、goroutine 的注意事项

闭包中的变量捕获问题

package main

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

var wg sync.WaitGroup

func main() {
	wg.Add(3)
	for i := 1; i <= 3; i++ {
		go func() {
			time.Sleep(time.Second)
			fmt.Println(i)
			wg.Done()
		}()
	}
	wg.Wait() // 等待所有 goroutine 完成
}

正确做法是将变量作为参数传进去:

package main

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

var wg sync.WaitGroup

func main() {
	wg.Add(3)
	for i := 1; i <= 3; i++ {
		go func(val int) {
			time.Sleep(time.Second)
			fmt.Println(val)
			wg.Done()
		}(i)
	}
	wg.Wait() // 等待所有 goroutine 完成
}