答案:高并发下Go日志写入需避免数据竞争,可通过Mutex加锁或channel异步队列实现线程安全;前者简单但性能低,后者解耦生产消费、支持缓冲,结合lumberjack还可实现轮转,推荐高并发场景使用。

在高并发场景下,多个协程同时写入日志容易引发数据竞争、文件损坏或日志错乱。Golang 虽然没有内置的并发安全日志系统,但通过合理设计可以轻松构建一个高效、线程安全的日志模块。以下是实战中常用的多协程文件写入方案。
使用互斥锁(Mutex)保护文件写入
最直接的方式是用 sync.Mutex 保证同一时间只有一个协程能执行写操作。
示例代码:
package mainimport ("log""os""sync")
var (file os.Filemu sync.Mutexlogger log.Logger)
func init() {var err errorfile, err = os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)if err != nil {log.Fatal("无法打开日志文件:", err)}logger = log.New(file, "", log.LstdFlags)}
func Log(message string) {mu.Lock()defer mu.Unlock()logger.Println(message)}
func main() {defer file.Close()
var wg sync.WaitGroupfor i := 0; i < 100; i++ { wg.Add(1) go func(id int) { defer wg.Done() Log("来自协程 " + string(rune(id+'0'))) }(i)}wg.Wait()
}
优点:实现简单,逻辑清晰。缺点:高并发下锁竞争严重,性能下降。
使用 channel 实现日志队列异步写入
更高效的方案是引入消息队列模型,所有协程将日志发送到 channel,由单个写入协程处理落盘。
立即学习“go语言免费学习笔记(深入)”;
改进版示例:
package mainimport ("bufio""log""os")
type Logger struct {ch chan string}
func NewLogger(filename string, bufferSize int) *Logger {l := &Logger{ch: make(chan string, bufferSize),}file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)if err != nil {log.Fatal("打开日志文件失败:", err)}
writer := bufio.NewWriter(file)go func() { for line := range l.ch { _, _ = writer.WriteString(line + "n") _ = writer.Flush() // 可根据性能需求调整是否实时 flush } _ = writer.Flush() _ = file.Close()}()return l
}
func (l *Logger) Log(msg string) {select {case l.ch
func main() {logger := NewLogger("async.log", 1000)
var wg sync.WaitGroupfor i := 0; i < 1000; i++ { wg.Add(1) go func(id int) { defer wg.Done() logger.Log("处理完成 - ID:" + strconv.Itoa(id)) }(i)}wg.Wait()// 简单等待,实际中可用 context 或 close channel 控制退出time.Sleep(time.Second)
}
优势:写入协程串行化,避免锁开销;生产消费解耦;支持缓冲和背压控制。
结合轮转(Rotate)与并发安全设计
真实项目中还需考虑日志文件大小限制和轮转。可封装第三方库如 lumberjack 配合上述模式使用。
集成 lumberjack 示例:
import ( "gopkg.in/natefinch/lumberjack.v2" "log")func NewRotatingLogger() *log.Logger {writer := &lumberjack.Logger{Filename: "logs/app.log",MaxSize: 10, // MBMaxBackups: 5,MaxAge: 7, // 天Compress: true,}return log.New(writer, "", log.LstdFlags)}
lumberjack 本身是线程安全的,可直接用于多协程环境。若配合 channel 模式,性能更优且不影响主流程响应速度。
基本上就这些。选择哪种方案取决于性能要求和系统复杂度。小项目用 Mutex 足够,高并发服务推荐 channel + 异步写入模型。关键是避免多个 goroutine 直接操作同一个文件句柄。
以上就是Golang 如何编写并发安全的日志系统_Golang 多协程文件写入方案实战的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1426713.html
微信扫一扫
支付宝扫一扫