Go语言实战案例:使用 Goroutine 并发打印

在本篇文章中,我们将从最基础的 Goroutine 并发模型入手,逐步掌握 Go 语言中并发控制的核心思想。通过一个简单的"并发打印任务"案例,掌握 Goroutine 的使用、输出顺序的控制、主协程退出时机等关键知识。


一、为什么学习 Goroutine?

Goroutine 是 Go 语言最核心的并发原语。相比于线程,它更加轻量:

  • 启动成本极低(大约只需 2KB 内存)
  • 数量可以轻松达到上万甚至百万级
  • 使用非常简单,只需一个 go 关键字

Go 的并发理念是:不要通过共享内存来通信,而要通过通信来共享内存。

掌握 Goroutine,是理解 Go 并发模型的第一步。


二、实战目标

我们将实现一个小项目:

  1. 启动多个 Goroutine 并发打印任务信息
  2. 每个任务打印固定内容
  3. 确保主程序等待所有任务完成
  4. 引入 sync.WaitGroup 实现同步控制

三、基础版本:启动多个 Goroutine

下面是最简单的 Goroutine 并发打印实现:

go 复制代码
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 正在执行
主程序结束

你会注意到,输出顺序可能与代码中的顺序不同,这是并发执行的结果。


四、问题:主程序过早退出

在上面例子中我们使用了 time.Sleep 来"凑时间",这是一种不可靠且危险的方式。如果任务执行时间更长,就会被主程序强制退出。

为了解决这个问题,我们引入 sync.WaitGroup


五、进阶版本:使用 WaitGroup 等待所有 Goroutine 完成

go 复制代码
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. go 关键字

只需在函数前加 go,即可将该函数交由调度器异步执行,立即返回

2. sync.WaitGroup

  • wg.Add(n):添加 n 个任务
  • wg.Done():在任务完成后调用
  • wg.Wait():阻塞主线程,直到所有任务完成

3. defer 用法

使用 defer wg.Done() 可以确保即使函数中途返回也能正确减计数。


七、延伸思考

  • 若有 10万个任务要并发执行,Goroutine 是否能承载?(答案是:可以,但建议使用并发控制池)
  • 如果某个任务失败,是否能提前取消其他任务?(答案是:可以结合 context 实现)

八、真实应用场景举例

  • 批量调用多个接口(如:并发请求天气接口、发邮件)
  • 批量处理文件(压缩、上传、转码)
  • 并发爬虫(抓取多个页面)
  • 消息队列并发消费任务

九、小结

本文通过"并发打印任务"这一简单示例,向你展示了 Go 并发编程的基本能力:

  • 启动 Goroutine 的方法
  • 并发任务间的非确定性
  • 如何使用 WaitGroup 来保证主程序的正确退出
  • Goroutine 的轻量特性,适合高并发场景

并发是 Go 的灵魂,控制好协程的生命周期和调度能力,将直接影响系统的健壮性与性能。

相关推荐
飞哥数智坊7 小时前
AI编程实战:使用Trae从零开始实现写作助手的后端开发及前后端联调
人工智能·trae
豆包MarsCode10 小时前
插件升级:Chat/Builder 合并,支持自定义 Agent、MCP、Rules
trae
逐光而行10 小时前
【AI coding】React对接后端接口实现入门级小工具todolist
trae
你不会困12 小时前
看看Trae怎么实现五彩斑斓的黑
trae
亿刀12 小时前
【go语言基础】slice
go
五岁小孩吖13 小时前
Go 单元测试 testing 包详解(testing.T、M、B、PB)
go
用户40993225021213 小时前
FastAPI后台任务为何能让邮件发送如此丝滑?
后端·github·trae
楽码15 小时前
一文看懂GO新版映射实现SwissTable
后端·算法·go
Code季风17 小时前
什么是微服务分布式配置中心?
分布式·微服务·go