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.WaitGroupchannel 等待 goroutine 完成
  • 使用 sync.Mutex 保护共享数据
  • 避免在 goroutine 中直接修改外部变量(使用参数传递)
相关推荐
悟空码字18 小时前
四轮对话两张配图:用 WorkBuddy 优化公众号发文配图的实战指南
人工智能·后端·腾讯
ServBay18 小时前
xAI的 Grok Bot发布,AI 已经学会自己上班了
后端·ai编程·grok
分支预测失败18 小时前
RISC-V 多核缓存一致性机制解析:MESI 协议族、CMO 扩展与 Linux 同步原语
后端
n8n18 小时前
Spring AI 检索增强生成(RAG)实战:让模型掌握你的私有知识
后端
Nturmoils19 小时前
只备份一个 schema,别把整库都搬走
后端
妙码生花19 小时前
利用AI从零学Go并完成实战项目,完工总结:目录结构
前端·后端·go
妙码生花19 小时前
利用AI从零学Go并完成实战项目,完工总结:商业级开源产品定位和核心特性介绍
前端·后端·go
程序员cxuan19 小时前
GPT-6 Astra 的提示词泄露了,里面居然藏着个保安?
人工智能·后端·程序员
苍何19 小时前
WorkBuddy + 飞书的 8 种神仙用法(建议收藏)
后端
Captaincc19 小时前
掘金AI用量统计v0.1.0大更新-支持桌面宠物自定义和订阅额度卡片
前端·后端