面试题答案
一键面试避免日志写入竞争条件
- 使用
sync.Mutex
:- 在写日志函数中使用
sync.Mutex
来保护日志写入操作。例如:
package main import ( "fmt" "sync" ) var ( mu sync.Mutex logFile = "app.log" ) func writeLog(message string) { mu.Lock() defer mu.Unlock() // 实际的日志写入文件操作,这里简单打印代替 fmt.Println(message) }
- 当多个goroutine调用
writeLog
函数时,sync.Mutex
会保证同一时间只有一个goroutine能够执行日志写入操作,从而避免竞争条件。
- 在写日志函数中使用
- 使用
sync.RWMutex
(适用于读多写少场景):- 如果存在大量的日志读取操作(例如查看日志)和少量的写入操作,可以使用
sync.RWMutex
。写操作时使用Lock
,读操作时使用RLock
。
package main import ( "fmt" "sync" ) var ( rwmu sync.RWMutex logContent string ) func writeLog(message string) { rwmu.Lock() defer rwmu.Unlock() logContent += message + "\n" } func readLog() string { rwmu.RLock() defer rwmu.RUnlock() return logContent }
- 如果存在大量的日志读取操作(例如查看日志)和少量的写入操作,可以使用
实现高效的异步日志记录
- 使用
channel
:- 创建一个日志消息的
channel
,并启动一个专门的goroutine来处理日志写入。
package main import ( "fmt" ) func main() { logChan := make(chan string) go func() { for message := range logChan { // 实际的日志写入文件操作,这里简单打印代替 fmt.Println(message) } }() // 模拟多个goroutine写日志 for i := 0; i < 10; i++ { go func(num int) { logChan <- fmt.Sprintf("Log message from goroutine %d", num) }(i) } // 等待所有日志写入完成后关闭channel select {} }
- 这样,各个goroutine只需要将日志消息发送到
channel
,而日志写入操作由专门的goroutine异步处理,提高了并发性能。
- 创建一个日志消息的
- 结合
sync.WaitGroup
:- 当需要确保所有日志消息都被处理完程序才退出时,可以结合
sync.WaitGroup
。
package main import ( "fmt" "sync" ) func main() { logChan := make(chan string) var wg sync.WaitGroup go func() { defer close(logChan) for message := range logChan { // 实际的日志写入文件操作,这里简单打印代替 fmt.Println(message) wg.Done() } }() // 模拟多个goroutine写日志 for i := 0; i < 10; i++ { wg.Add(1) go func(num int) { logChan <- fmt.Sprintf("Log message from goroutine %d", num) }(i) } wg.Wait() }
sync.WaitGroup
确保所有日志消息都被处理完毕,程序才会正常退出。
- 当需要确保所有日志消息都被处理完程序才退出时,可以结合