0

0

Goroutines 的工作原理及主进程结束后 Goroutines 的生命周期

碧海醫心

碧海醫心

发布时间:2025-10-08 11:18:38

|

624人浏览过

|

来源于php中文网

原创

goroutines 的工作原理及主进程结束后 goroutines 的生命周期

Goroutines 是 Go 语言并发编程的核心。理解 Goroutines 的工作方式以及它们在主进程结束后的行为至关重要。本文将深入探讨 Goroutines 的生命周期,以及如何使用 sync.WaitGroup 来确保 Goroutines 完成任务。

Goroutines 的基本概念

Goroutines 本质上是轻量级的线程,由 Go 运行时(runtime)管理。与传统的线程相比,Goroutines 的创建和销毁开销更小,切换速度更快,因此可以在程序中创建大量的 Goroutines 来实现并发执行。

当程序启动时,会创建一个主 Goroutine 来执行 main 函数。可以通过 go 关键字来启动新的 Goroutines,每个 Goroutine 都会并发地执行指定的函数。

package main

import (
    "fmt"
    "time"
)

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        go worker(i)
    }

    // 暂停几秒钟,让 worker 线程有机会运行
    time.Sleep(time.Second * 2)
}

在这个例子中,main 函数启动了三个 Goroutines,每个 Goroutine 执行 worker 函数。worker 函数会打印一条消息,暂停一秒钟,然后再次打印一条消息。main 函数暂停了两秒钟,以便让 Goroutines 有机会完成执行。

Goroutines 的生命周期

Goroutines 的生命周期始于 go 关键字的调用,终于函数的执行完成。需要注意的是,当 main 函数返回时,程序会立即退出,不会等待其他 Goroutines 完成执行。这意味着,如果 main 函数在 Goroutines 完成之前退出,那么这些 Goroutines 就会被强制终止,可能导致数据丢失或程序状态不一致。

使用 sync.WaitGroup 管理 Goroutines

为了确保 Goroutines 完成任务后再退出程序,可以使用 sync.WaitGroup。sync.WaitGroup 提供了一种简单的机制来等待一组 Goroutines 完成执行。

sync.WaitGroup 的使用步骤如下:

TTSMaker
TTSMaker

TTSMaker是一个免费的文本转语音工具,提供语音生成服务,支持多种语言。

下载
  1. 创建 sync.WaitGroup 实例:在 main 函数中创建一个 sync.WaitGroup 实例。
  2. 增加计数器:在启动每个 Goroutine 之前,调用 wg.Add(1) 来增加计数器。
  3. 标记完成:在每个 Goroutine 的结束处,调用 wg.Done() 来标记完成,减少计数器。
  4. 等待完成:在 main 函数中,调用 wg.Wait() 来等待计数器归零,即所有 Goroutines 都已完成。
package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 确保在函数退出时调用 Done()

    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1) // 启动一个 worker 线程,增加计数器
        go worker(i, &wg)
    }

    wg.Wait() // 阻塞直到计数器归零
    fmt.Println("All workers done")
}

在这个例子中,main 函数在启动每个 worker Goroutine 之前调用 wg.Add(1),在 worker 函数的结束处调用 wg.Done()。main 函数调用 wg.Wait() 来等待所有 worker Goroutines 完成执行。

示例:并发插入 MongoDB

以下代码演示了如何使用 Goroutines 和 sync.WaitGroup 并发地向 MongoDB 插入数据。

package main

import (
    "fmt"
    "labix.org/v2/mgo"
    "strconv"
    "sync"
    "time"
)

// Reading 结构体
type Reading struct {
    Id   string
    Name string
}

func main() {
    // 设置计时器
    startTime := time.Now()

    // 设置集合
    collection := getCollection("test", "readings")
    fmt.Println("collection complete: " + strconv.FormatFloat(time.Since(startTime).Seconds(), 'f', 2, 64))

    // 准备 readings
    readings := prepareReadings()
    fmt.Println("readings prepared: " + strconv.FormatFloat(time.Since(startTime).Seconds(), 'f', 2, 64))

    var waitGroup sync.WaitGroup

    // 插入 readings
    for i := 1; i <= 1000000; i++ {
        waitGroup.Add(1)
        go insertReadings(collection, readings, &waitGroup)

        if i%100000 == 0 {
            fmt.Println("100000 readings queued for insert: " + strconv.FormatFloat(time.Since(startTime).Seconds(), 'f', 2, 64))
        }
    }
    waitGroup.Wait()

    fmt.Println("all readings inserted: " + strconv.FormatFloat(time.Since(startTime).Seconds(), 'f', 2, 64))
}

func getCollection(databaseName string, tableName string) *mgo.Collection {
    session, err := mgo.Dial("localhost")

    if err != nil {
        fmt.Println("error getCollection:", err)
        panic(err)
    }

    collection := session.DB(databaseName).C(tableName)

    return collection
}

func insertReadings(collection *mgo.Collection, readings []Reading, waitGroup *sync.WaitGroup) {
    defer waitGroup.Done()

    err := collection.Insert(readings)

    if err != nil {
        fmt.Println("error insertReadings:", err)
    }
}

func prepareReadings() []Reading {
    var readings []Reading
    for i := 1; i <= 1; i++ {
        readings = append(readings, Reading{Name: "Thing"})
    }

    return readings
}

在这个例子中,insertReadings 函数接收一个 sync.WaitGroup 指针,并在函数结束时调用 waitGroup.Done()。main 函数在启动每个 insertReadings Goroutine 之前调用 waitGroup.Add(1),并使用 waitGroup.Wait() 等待所有 Goroutines 完成。

注意事项:

  • 确保在每个 Goroutine 中都调用 defer wg.Done(),以避免 Goroutine 提前退出导致程序死锁。
  • 并发访问共享资源时,需要使用互斥锁(sync.Mutex)或其他同步机制来保护数据的一致性。

总结

Goroutines 是 Go 语言并发编程的强大工具。通过理解 Goroutines 的生命周期以及如何使用 sync.WaitGroup,可以编写出高效、可靠的并发程序。在实际开发中,需要根据具体情况选择合适的并发模型,并注意数据同步和资源竞争的问题。

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

471

2023.08.10

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

280

2023.07.18

mongodb启动命令
mongodb启动命令

MongoDB 是一种开源的、基于文档的 NoSQL 数据库管理系统。本专题提供mongodb启动命令的文章,希望可以帮到大家。

246

2023.08.08

MongoDB删除数据的方法
MongoDB删除数据的方法

MongoDB删除数据的方法有删除集合中的文档、删除整个集合、删除数据库和删除指定字段等。本专题为大家提供MongoDB相关的文章、下载、课程内容,供大家免费下载体验。

159

2023.09.19

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

954

2023.11.02

mongodb有哪些应用领域
mongodb有哪些应用领域

mongodb 的应用领域涵盖广泛,包括内容管理系统、社交媒体、分析、移动应用、物联网、金融科技、医疗保健和广告技术等领域,因其灵活性、可扩展性和易用性而广受欢迎。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

333

2024.04.02

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

471

2024.04.02

mongodb安装失败如何彻底删除
mongodb安装失败如何彻底删除

彻底删除 mongodb 安装失败的步骤:1、停止和禁用 mongodb 服务;2、删除配置文件、数据目录和日志文件;3、删除 mongodb 二进制文件;4、卸载 mongodb 套件(如果通过软件包管理器安装);5、删除 mongodb 用户、组和目录;6、重启系统。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

372

2024.04.02

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.2万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号