0

0

Go 协程调度与程序退出时机:奇偶循环次数的影响

霞舞

霞舞

发布时间:2025-10-17 08:11:21

|

554人浏览过

|

来源于php中文网

原创

go 协程调度与程序退出时机:奇偶循环次数的影响

本文探讨了 Go 语言中一个有趣的现象:当循环次数为奇数时,Go 程序能够完整输出所有数据,而当循环次数为偶数时,程序可能会丢失最后一个数据。我们将分析这种现象背后的原因,并提供解决方案,确保程序在退出前能够正确处理所有协程。

在 Go 语言中,协程(goroutine)是轻量级的并发执行单元。理解 Go 协程的调度机制以及程序退出时机的关系对于编写健壮的并发程序至关重要。以下代码展示了一个可能导致数据丢失的场景:

package main

import "runtime"
import "sync"

func main() {
    c2 := make(chan int)
    var wg sync.WaitGroup

    wg.Add(1)
    go func() {
        defer wg.Done()
        for v := range c2 {
            println("c2 =", v, "numof routines:", runtime.NumGoroutine())
        }
    }()

    for i := 1; i <= 10000; i++ { // 尝试修改为 10001
        c2 <- i
    }
    close(c2) // 关闭channel,通知goroutine退出
    wg.Wait() // 等待goroutine完成
}

上述代码创建了一个协程,该协程从 channel c2 中读取数据并打印。主协程向 c2 中写入数据。一个有趣的现象是,当循环次数为偶数(例如 10000)时,程序可能无法打印所有数据,而当循环次数为奇数(例如 10001)时,程序通常能够完整输出。

原因分析

这种现象的原因在于 Go 程序的退出机制。当 main 函数返回时,程序会立即终止,而不会等待其他协程完成。在上述代码中,如果 main 函数在协程处理完所有数据之前返回,那么部分数据可能无法被打印。

奇偶循环次数的影响仅仅是表面现象,其本质是协程的调度和 main 函数的退出时机存在竞争关系。循环次数的微小变化可能导致 main 函数提前或延迟退出,从而影响协程是否能够完成所有任务。这本质上是一种概率问题,受到 Go 调度器的影响。

拍我AI
拍我AI

AI视频生成平台PixVerse的国内版本

下载

解决方案

为了确保程序在退出前能够正确处理所有协程,可以使用 sync.WaitGroup 来同步协程的完成状态。以下是修改后的代码:

package main

import "runtime"
import "sync"

func main() {
    c2 := make(chan int)
    var wg sync.WaitGroup

    wg.Add(1) // 增加等待计数器
    go func() {
        defer wg.Done() // 协程退出时减少计数器
        for v := range c2 {
            println("c2 =", v, "numof routines:", runtime.NumGoroutine())
        }
    }()

    for i := 1; i <= 10000; i++ { // 尝试修改为 10001
        c2 <- i
    }
    close(c2) // 关闭channel,通知goroutine退出
    wg.Wait() // 等待计数器归零,即等待goroutine完成
}

在这个修改后的版本中,sync.WaitGroup 用于等待协程完成。wg.Add(1) 增加等待计数器,wg.Done() 在协程退出时减少计数器,wg.Wait() 阻塞 main 函数,直到计数器归零,即所有协程都已完成。

此外,close(c2) 的调用至关重要。它通知协程不再有新的数据写入 channel,从而使协程能够正常退出。

总结

Go 协程的调度和程序退出时机是并发编程中需要重点关注的问题。通过使用 sync.WaitGroup 和正确关闭 channel,可以确保程序在退出前能够正确处理所有协程,避免数据丢失和其他潜在问题。在编写并发程序时,务必考虑协程的生命周期和同步机制,以确保程序的健壮性和可靠性。

相关专题

更多
Golang channel原理
Golang channel原理

本专题整合了Golang channel通信相关介绍,阅读专题下面的文章了解更多详细内容。

247

2025.11.14

golang channel相关教程
golang channel相关教程

本专题整合了golang处理channel相关教程,阅读专题下面的文章了解更多详细内容。

342

2025.11.17

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

3

2026.01.21

无人机驾驶证报考 uom民用无人机综合管理平台官网
无人机驾驶证报考 uom民用无人机综合管理平台官网

无人机驾驶证(CAAC执照)报考需年满16周岁,初中以上学历,身体健康(矫正视力1.0以上,无严重疾病),且无犯罪记录。个人需通过民航局授权的训练机构报名,经理论(法规、原理)、模拟飞行、实操(GPS/姿态模式)及地面站训练后考试合格,通常15-25天拿证。

14

2026.01.21

Python多线程合集
Python多线程合集

本专题整合了Python多线程相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.21

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.21

windows激活码分享 windows一键激活教程指南
windows激活码分享 windows一键激活教程指南

Windows 10/11一键激活可以通过PowerShell脚本或KMS工具实现永久或长期激活。最推荐的简便方法是打开PowerShell(管理员),运行 irm https://get.activated.win | iex 脚本,按提示选择数字激活(选项1)。其他方法包括使用HEU KMS Activator工具进行智能激活。

2

2026.01.21

excel表格操作技巧大全 表格制作excel教程
excel表格操作技巧大全 表格制作excel教程

Excel表格操作的核心技巧在于 熟练使用快捷键、数据处理函数及视图工具,如Ctrl+C/V(复制粘贴)、Alt+=(自动求和)、条件格式、数据验证及数据透视表。掌握这些可大幅提升数据分析与办公效率,实现快速录入、查找、筛选和汇总。

6

2026.01.21

热门下载

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

精品课程

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

共32课时 | 4万人学习

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号