文章目录
目录
- 一、为什么学习 Goroutine?
- 二、实战目标
- 三、基础版本:启动多个 Goroutine
- 运行结果(示例):
- 四、问题:主程序过早退出
- 五、进阶版本:使用 WaitGroup 等待所有 Goroutine 完成
- 输出示例:
- 六、重点知识点解析
- 1.go关键字
- 2.sync.WaitGroup
- 3.defer用法
- 七、延伸思考
- 八、真实应用场景举例
- 九、小结
在本篇文章中,我们将从最基础的 Goroutine 并发模型入手,逐步掌握 Go 语言中并发控制的核心思想。通过一个简单的“并发打印任务”案例,掌握 Goroutine 的使用、输出顺序的控制、主协程退出时机等关键知识。
Goroutine 是 Go 语言最核心的并发原语。相比于线程,它更加轻量:
- 启动成本极低(大约只需 2KB 内存)
- 数量可以轻松达到上万甚至百万级
- 使用非常简单,只需一个
go关键字
Go 的并发理念是:不要通过共享内存来通信,而要通过通信来共享内存。
掌握 Goroutine,是理解 Go 并发模型的第一步。
我们将实现一个小项目:
- 启动多个 Goroutine 并发打印任务信息
- 每个任务打印固定内容
- 确保主程序等待所有任务完成
- 引入
sync.WaitGroup实现同步控制
下面是最简单的 Goroutine 并发打印实现:
package main
import (
"fmt"
"time"
)
func printTask(id int) {
fmt.Printf("任务 %d 正在执行n", id)
}
func main() {
for i := 1; i <= 5; i++ {
go printTask(i)
}
// 给协程一点时间完成(不推荐的方式)
time.Sleep(time.Second)
fmt.Println("主程序结束")
}
任务 2 正在执行
任务 4 正在执行
任务 1 正在执行
任务 3 正在执行
任务 5 正在执行
主程序结束
任务 2 正在执行
任务 4 正在执行
任务 1 正在执行
任务 3 正在执行
任务 5 正在执行
主程序结束
你会注意到,输出顺序可能与代码中的顺序不同,这是并发执行的结果。
在上面例子中我们使用了 time.Sleep 来“凑时间”,这是一种不可靠且危险的方式。如果任务执行时间更长,就会被主程序强制退出。
为了解决这个问题,我们引入 sync.WaitGroup。
package main
import (
"fmt"
"sync"
"time"
)
// 模拟执行任务
func printTask(id int, wg *sync.WaitGroup) {
defer wg.Done() // 标记一个任务完成
fmt.Printf("任务 %d 开始执行n", id)
time.Sleep(time.Duration(id) * 200 * time.Millisecond) // 模拟不同任务耗时
fmt.Printf("任务 %d 执行完毕n", id)
}
func main() {
var wg sync.WaitGroup
taskCount := 5
for i := 1; i <= taskCount; i++ {
wg.Add(1) // 增加一个任务
go printTask(i, &wg)
}
wg.Wait() // 等待所有任务完成
fmt.Println("所有任务完成,主程序退出")
}
任务 1 开始执行
任务 2 开始执行
任务 3 开始执行
任务 4 开始执行
任务 5 开始执行
任务 1 执行完毕
任务 2 执行完毕
任务 3 执行完毕
任务 4 执行完毕
任务 5 执行完毕
所有任务完成,主程序退出
任务 1 开始执行
任务 2 开始执行
任务 3 开始执行
任务 4 开始执行
任务 5 开始执行
任务 1 执行完毕
任务 2 执行完毕
任务 3 执行完毕
任务 4 执行完毕
任务 5 执行完毕
所有任务完成,主程序退出
只需在函数前加 go,即可将该函数交由调度器异步执行,立即返回。
wg.Add(n):添加 n 个任务
wg.Done():在任务完成后调用
wg.Wait():阻塞主线程,直到所有任务完成
wg.Add(n):添加 n 个任务wg.Done():在任务完成后调用wg.Wait():阻塞主线程,直到所有任务完成
使用 defer wg.Done() 可以确保即使函数中途返回也能正确减计数。
- 若有 10万个任务要并发执行,Goroutine 是否能承载?(答案是:可以,但建议使用并发控制池)
- 如果某个任务失败,是否能提前取消其他任务?(答案是:可以结合
context 实现)
context 实现)
- 批量调用多个接口(如:并发请求天气接口、发邮件)
- 批量处理文件(压缩、上传、转码)
- 并发爬虫(抓取多个页面)
- 消息队列并发消费任务
本文通过“并发打印任务”这一简单示例,向你展示了 Go 并发编程的基本能力:
- 启动 Goroutine 的方法
- 并发任务间的非确定性
- 如何使用 WaitGroup 来保证主程序的正确退出
- Goroutine 的轻量特性,适合高并发场景
并发是 Go 的灵魂,控制好协程的生命周期和调度能力,将直接影响系统的健壮性与性能。
到此这篇关于Go语言使用Goroutine并发打印的项目实践的文章就介绍到这了,更多相关Go Goroutine并发打印内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!
您可能感兴趣的文章:
- golang gin 框架 异步同步 goroutine 并发操作
- Go语言中的并发goroutine底层原理
- Go并发编程之goroutine使用正确方法
- Go 并发编程Goroutine的实现示例
- Golang 语言控制并发 Goroutine的方法
- golang并发编程中Goroutine 协程的实现
- Go中Goroutines轻量级并发的特性及效率探究
- 使用Go goroutine实现并发的Clock服务
- Go语言使用goroutine及通道实现并发详解
- Go 控制协程(goroutine)的并发数量