0

0

Go 并发编程中保证原子性输出的正确方法

DDD

DDD

发布时间:2025-08-20 08:40:14

|

516人浏览过

|

来源于php中文网

原创

go 并发编程中保证原子性输出的正确方法

在 Go 并发编程中,有时我们需要保证特定操作的原子性,例如,防止多个 Goroutine 的打印输出混杂在一起。 很多人可能会尝试使用 runtime.LockOSThread() 和 runtime.UnlockOSThread() 来实现,但这种方法通常无法达到预期的效果。 本文将探讨为什么这种方法会失效,并提供更合适的解决方案。

正如上面摘要所说,直接使用runtime.LockOSThread()和runtime.UnlockOSThread()并不能保证多个Goroutine之间的打印输出顺序。这是因为它们主要用于将 Goroutine 绑定到特定的操作系统线程,主要目的是为了与某些需要线程亲和性的 C 库进行交互,而非控制 Goroutine 的执行顺序。

为什么 runtime.LockOSThread() 和 runtime.UnlockOSThread() 不适用于原子性输出?

runtime.LockOSThread() 将 Goroutine 绑定到一个操作系统线程,这意味着该 Goroutine 将始终在该线程上执行,直到调用 runtime.UnlockOSThread() 解除绑定。 然而,这并不意味着其他 Goroutine 不能在其他线程上执行,因此打印输出仍然可能交错。

正确的解决方案:序列化打印任务

为了保证原子性输出,我们需要对打印操作进行序列化,确保同一时刻只有一个 Goroutine 可以执行打印任务。以下是两种常用的方法:

1. 使用互斥锁(Mutex)

可以使用 sync.Mutex 来保护打印操作。 每个 Goroutine 在执行打印操作之前,需要先获取锁,完成打印后释放锁。

import (
    "fmt"
    "sync"
)

var printMutex sync.Mutex

func printSomething(message string) {
    printMutex.Lock()
    defer printMutex.Unlock() // 确保在函数退出时释放锁
    fmt.Println(message)
}

func routine(id int) {
    for i := 0; i < 5; i++ {
        printSomething(fmt.Sprintf("Routine %d: Message %d", id, i))
    }
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 2; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            routine(id)
        }(i)
    }
    wg.Wait()
}

注意事项:

AMiner
AMiner

AMiner——新一代智能型科技情报挖掘与服务系统,能够为你提供查找论文、理解论文、分析论文、写作论文四位一体一站式服务。

下载
  • 使用互斥锁需要小心,避免死锁。如果多个 Goroutine 相互等待对方释放锁,就会发生死锁。
  • 对于复杂的程序,互斥锁可能会引入性能瓶颈。

2. 使用通道(Channel)

更优雅的方式是使用通道来传递打印任务。 创建一个专门负责打印的 Goroutine (printer),其他 Goroutine 将需要打印的内容发送到该通道,printer Goroutine 接收任务并按顺序打印。

import (
    "fmt"
    "sync"
)

func printer(tasks <-chan string) {
    for s := range tasks {
        fmt.Println(s)
    }
}

func someAgent(id int, tasks chan<- string, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        printUnit := fmt.Sprintf("Agent %d: Message %d", id, i)
        tasks <- printUnit
    }
}

func main() {
    tasks := make(chan string, 10) // 创建一个带缓冲的通道,避免阻塞
    var wg sync.WaitGroup

    go printer(tasks) // 启动打印 Goroutine

    for i := 1; i <= 2; i++ {
        wg.Add(1)
        go someAgent(i, tasks, &wg)
    }

    wg.Wait()
    close(tasks) // 关闭通道,通知 printer Goroutine 任务完成
}

优点:

  • 避免死锁:因为 Goroutine 之间通过通道传递数据,不存在相互等待锁的情况。
  • 解耦:打印逻辑与业务逻辑分离,代码更清晰。
  • 易于扩展:可以轻松添加更多的打印任务。

注意事项:

  • 需要合理设置通道的容量,避免阻塞。
  • 在所有任务完成后,需要关闭通道,通知 printer Goroutine 退出。

总结

在 Go 并发编程中,要保证原子性输出,不能依赖 runtime.LockOSThread() 和 runtime.UnlockOSThread()。 更有效的方法是使用互斥锁或通道来序列化打印任务。 其中,使用通道的方式更加优雅,可以避免死锁,并提高代码的可维护性。 根据实际情况选择合适的解决方案,可以有效地解决并发环境下的原子性问题。

相关文章

编程速学教程(入门课程)
编程速学教程(入门课程)

编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

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

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

482

2023.08.10

Golang channel原理
Golang channel原理

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

247

2025.11.14

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

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

343

2025.11.17

c++ 根号
c++ 根号

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

25

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

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

29

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

117

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

178

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

16

2026.01.23

php远程文件教程合集
php远程文件教程合集

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

70

2026.01.22

热门下载

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

精品课程

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

共28课时 | 4.8万人学习

PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.8万人学习

Git 教程
Git 教程

共21课时 | 3万人学习

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

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