0

0

如何使用Golang实现并发日志写入_Golang多goroutine日志记录方法

P粉602998670

P粉602998670

发布时间:2026-01-10 16:23:03

|

612人浏览过

|

来源于php中文网

原创

直接用 log.Printf 在多 goroutine 中写文件会出问题,因为 log.Logger 默认不并发安全,格式化与写入非原子操作,易致日志错乱、截断或 panic。

如何使用golang实现并发日志写入_golang多goroutine日志记录方法

为什么直接用 log.Printf 在多 goroutine 中写文件会出问题

因为标准库log.Logger 默认不保证并发安全——多个 goroutine 同时调用 logger.Print() 可能导致日志行错乱、截断,甚至 panic(比如底层 os.File.Write 被并发调用时触发内部锁竞争或缓冲区越界)。这不是“偶尔出错”,而是在高并发写入场景下几乎必然发生。

  • 典型现象:2024-05-12T10:23:41Z INFO user login2024-05-12T10:23:41Z ERROR db timeout 混合成一行,如 2024-05-12T10:23:41Z INFO user login2024-05-12T10:23:41Z ERROR db timeout
  • 根本原因:日志格式化 + 写入不是原子操作;log.LoggerOutput 方法内部未对写入目标加锁
  • 误区:以为给 log.New 传一个带互斥锁的 io.Writer 就够了——其实还不够,因为格式化字符串(含时间、调用)本身也需同步,否则不同 goroutine 的 runtime.Caller 信息可能交叉

sync.Mutex 包裹 log.Logger 是最简方案但有性能瓶颈

适用于 QPS

var (
    mu     sync.Mutex
    logger = log.New(os.Stdout, "", log.LstdFlags)
)

func SafeLog(msg string) { mu.Lock() defer mu.Unlock() logger.Println(msg) }

  • 不要在 log.New 里直接传 &muWriter{mu: &mu, w: file} 这类包装 writer——log.Logger 会在每次调用时重置缓冲区并多次调用 Write,仅锁 Write 无法防止格式化内容被其他 goroutine 插入
  • 如果必须用标准库,务必把整个 logger.Printlnlogger.Printf 调用包在 Lock/Unlock
  • 注意:log.SetOutput 不是并发安全的,不能在运行时动态切换输出目标

推荐用 zap.Logger 配合 zapcore.Lock 实现无锁高性能写入

zap 是 Uber 开源的结构化日志库,其 zapcore.Core 层原生支持并发写入。关键不是“加锁”,而是使用 zapcore.Lock 对底层 io.Writer 做最小粒度保护,同时保持格式化与写入分离的高效路径。

file, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
lockedWriter := zapcore.Lock(file)
core := zapcore.NewCore(
    zapcore.JSONEncoder{TimeKey: "ts", EncodeTime: zapcore.ISO8601TimeEncoder},
    lockedWriter,
    zapcore.InfoLevel,
)
logger := zap.New(core)

// 多个 goroutine 可安全调用 go func() { logger.Info("request started", zap.String("path", "/api/v1")) }() go func() { logger.Error("db failed", zap.Error(err)) }()

  • zapcore.Lock 只锁 Write 系统调用,不锁格式化过程,因此比全函数加锁快 3–5 倍(实测 10k 日志/秒场景)
  • 避免用 zap.NewDevelopmentzap.NewProduction 直接初始化——它们内部已封装了锁,但你无法控制 writer 生命周期;建议手动构造 Core 以明确管理文件句柄
  • 注意关闭:程序退出前需调用 logger.Sync(),否则最后几条日志可能滞留在缓冲区未刷盘

自研环形缓冲 + 单独写入 goroutine 更适合极端吞吐场景

当单机日志量 > 50MB/s 或要求毫秒级延迟可控时,zap 的锁仍可能成为瓶颈。此时应将日志事件投递到 channel,由专用 goroutine 顺序写入,并配合内存缓冲和批量刷盘。

立即学习go语言免费学习笔记(深入)”;

  • 核心结构:chan *LogEntry(固定长度,如 1024),LogEntry 包含预格式化字符串、时间戳、level 字段
  • 投递端不阻塞:用 select { case ch 防止日志堆积拖慢主逻辑
  • 写入端做合并:每 10ms 或积满 64 条后统一 Write,减少系统调用次数
  • 别忘了信号处理:收到 SIGTERM 时先 close channel,再等待写入 goroutine 完成剩余日志,最后 file.Close()

真正难的不是“怎么让多 goroutine 不写乱”,而是“怎么在不拖慢业务的前提下,把日志可靠落盘”。锁只是起点,缓冲策略、刷盘时机、错误降级(比如磁盘满时切到 syslog)、以及是否接受少量丢失——这些权衡点,往往比选哪个库更影响线上稳定性。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

177

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

226

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

336

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

208

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

388

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

194

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

189

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

191

2025.06.17

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

25

2026.01.09

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.2万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.1万人学习

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

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