Go语言-->Goroutine 详细解释

Goroutine 详细解释

goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理。它是实现并发编程的核心机制。

核心概念

特性 说明
轻量级 创建成本极低,一个程序可以轻松创建数百万个 goroutine
并发执行 多个 goroutine 可以同时运行
由运行时管理 Go 运行时自动调度 goroutine 到 CPU 核心上
非抢占式 goroutine 只在特定点(如 I/O、channel 操作)让出控制权

基本用法

1. 创建 Goroutine

go 复制代码
package main

import (
	"fmt"
	"time"
)

func main() {
	// 普通函数调用(同步)
	sayHello("Alice")
	
	// 启动 goroutine(异步)
	go sayHello("Bob")
	
	// 主 goroutine 需要等待子 goroutine 完成
	time.Sleep(1 * time.Second)
}

func sayHello(name string) {
	fmt.Printf("Hello, %s\n", name)
}

输出:

复制代码
Hello, Alice
Hello, Bob

2. 多个 Goroutine

go 复制代码
package main

import (
	"fmt"
	"time"
)

func main() {
	for i := 1; i <= 5; i++ {
		go func(id int) {
			fmt.Printf("Goroutine %d 开始\n", id)
			time.Sleep(time.Duration(id) * time.Second)
			fmt.Printf("Goroutine %d 完成\n", id)
		}(i)
	}
	
	// 等待所有 goroutine 完成
	time.Sleep(6 * time.Second)
	fmt.Println("主程序结束")
}

输出:

复制代码
Goroutine 1 开始
Goroutine 2 开始
Goroutine 3 开始
Goroutine 4 开始
Goroutine 5 开始
Goroutine 1 完成
Goroutine 2 完成
Goroutine 3 完成
Goroutine 4 完成
Goroutine 5 完成
主程序结束

go func() 和 go sayHello("Bob") 的区别

特性 go func() go sayHello("Bob")
类型 匿名函数 命名函数
定义位置 调用处定义 提前定义
代码量 适合简短逻辑 适合复杂逻辑
可重用性 不可重用 可重用
闭包 可访问外部变量 需要参数传递

Goroutine vs 线程

特性 Goroutine 线程
内存占用 ~2KB ~1-2MB
创建速度 极快 较慢
数量 可创建百万级 通常数百个
切换成本 低 高
管理 Go 运行时 操作系统

与 Channel 结合

go 复制代码
package main

import (
	"fmt"
)

func main() {
	// 创建 channel
	results := make(chan string)
	
	// 启动 goroutine
	go func() {
		results <- "任务 1 完成"
	}()
	
	go func() {
		results <- "任务 2 完成"
	}()
	
	// 接收结果
	fmt.Println(<-results)
	fmt.Println(<-results)
}

输出:

复制代码
任务 1 完成
任务 2 完成

常见模式

1. 使用 sync.WaitGroup 等待完成

go 复制代码
package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			fmt.Printf("Goroutine %d 执行\n", id)
		}(i)
	}
	
	wg.Wait()
	fmt.Println("所有 goroutine 完成")
}

2. 并发 HTTP 请求

go 复制代码
package main

import (
	"fmt"
	"net/http"
	"sync"
)

func main() {
	urls := []string{
		"https://example.com",
		"https://google.com",
		"https://github.com",
	}
	
	var wg sync.WaitGroup
	for _, url := range urls {
		wg.Add(1)
		go func(u string) {
			defer wg.Done()
			resp, err := http.Get(u)
			if err != nil {
				fmt.Printf("请求 %s 失败: %v\n", u, err)
			} else {
				fmt.Printf("请求 %s 成功,状态码: %d\n", u, resp.StatusCode)
			}
		}(url)
	}
	
	wg.Wait()
}

注意事项

⚠️ 常见问题:

  • 主 goroutine 过早退出:子 goroutine 还未完成就结束了
  • 竞态条件:多个 goroutine 同时修改共享变量
  • 死锁:goroutine 互相等待

✅ 最佳实践:

  • 使用 sync.WaitGroup 或 channel 等待 goroutine 完成
  • 使用 sync.Mutex 保护共享数据
  • 避免在 goroutine 中直接修改外部变量(使用参数传递)
相关推荐
代码不停7 小时前
自动化测试(java)
java·开发语言·selenium·自动化
行百里er8 小时前
Redis 完结篇——Redis 热点问题在 Spring Boot 项目中实战
redis·后端
高频因子挖掘机9 小时前
只取最近 60 个交易日,却每次拉全历史:量化脚本变慢的原因与改法
后端·github·api
鬼手点金9 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
爱上网的小舟9 小时前
星际战士2启动错误怎么办?5种游戏报错解决方法
开发语言·php
孟健10 小时前
从5000亿Token到83%字节匹配:AI逆向工程与重构的工程闭环实践
后端·架构·ai编程
阿里嘎多学长10 小时前
2026-10-12 GitHub 热点项目精选
开发语言·程序员·github·代码托管
码事漫谈10 小时前
丢得静悄悄,谈一谈 Agent 的记忆是怎么没的
后端
迪飞特科技10 小时前
智慧物业平台实战:Spring Boot 整合小程序实现报修巡检费用全流程
spring boot·后端·小程序
考虑考虑10 小时前
@JsonInclude注解使用
spring boot·后端·spring