使用互斥锁、通道或第三方库实现并发安全日志写入,推荐zap等高性能库以平衡安全性与性能。

在高并发场景下,多个Goroutine同时写入日志容易引发竞争问题,导致日志错乱或丢失。使用Golang实现安全的并发日志写入,关键在于同步控制和性能平衡。下面介绍几种实用方法。
使用互斥锁(Mutex)保护文件写入
最直接的方式是用sync.Mutex确保同一时间只有一个Goroutine能写入日志文件。
示例代码:
package mainimport ( "log" "os" "sync" )
var ( logFile *os.File mutex sync.Mutex )
func init() { var err error logFile, err = os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { log.Fatal(err) } log.SetOutput(logFile) }
func writeLog(message string) { mutex.Lock() defer mutex.Unlock() log.Println(message) }
func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(id int) { defer wg.Done() writeLog("来自 Goroutine 的日志:" + string(rune(id+'0'))) }(i) } wg.Wait() logFile.Close() }
优点:简单可靠;缺点:高并发时可能成为性能瓶颈。
立即学习“go语言免费学习笔记(深入)”;
使用通道(Channel)集中写入
通过一个专用的Goroutine负责实际写入,其他协程通过通道发送日志消息,避免直接竞争。
示例:
package mainimport ( "bufio" "os" )
var logChan = make(chan string, 100)
Kotlin Android 中文开发帮助文档 PDF版下载这本书并不是一本语言参考书,但它是一个Android开发者去学习Kotlin并且使用在自己项目中的一个工具。我会通过使用一些语言特性和有趣的工具和库来解决很多我们在日常生活当中都会遇到的典型问题。 这本书是非常具有实践性的,所以我建议你在电脑面前跟着我的例子和代码实践。无论何时你都可以在有一些想法的时候深入到实践中去。 这本书适合你吗? 写这本书是为了帮助那些有兴趣 使用Kotlin语言来进行开发的Android开发者。 如果你符合下面这些情况,那这本书是适合你的: 你有相关Android开发和Andro
func logger() { file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { panic(err) } defer file.Close()
writer := bufio.NewWriter(file) defer writer.Flush() for msg := range logChan { writer.WriteString(msg + "\n") }}
func init() { go logger() }
func writeLog(message string) { logChan
这种方式解耦了日志生产与消费,适合高并发环境,且可通过缓冲提升性能。
结合第三方库如 zap 或 logrus
uber-go/zap 和 sirupsen/logrus 等库原生支持并发安全的日志写入,底层已做优化。
以 zap 为例:
import "go.uber.org/zap"func main() { logger, _ := zap.NewProduction() defer logger.Sync()
var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func(id int) { defer wg.Done() logger.Info("并发日志", zap.Int("goroutine", id)) }(i) } wg.Wait()}
zap 性能优异,结构化输出清晰,推荐用于生产项目。
注意事项与建议
- 避免每个Goroutine频繁打开/关闭文件,应复用文件句柄
- 使用带缓冲的通道可减少阻塞,但需防止内存溢出
- 定期调用Sync()确保日志落盘
- 考虑按日期或大小轮转日志文件
基本上就这些。选择哪种方式取决于性能要求和系统复杂度。小项目用 Mutex 足够,中大型服务建议用 channel 模式或 zap 这类成熟库。关键是保证线程安全,同时不拖慢主业务逻辑。










