猿问

为什么 Logger.Output 在检查 Lshortfile/Llongfile 标志之

在 Go 的实现中(l *Logger) Output,为什么要先获取互斥锁 if l.flag&(Lshortfile|Llongfile) != 0 {?


func (l *Logger) Output(calldepth int, s string) error {

    now := time.Now() // get this early.

    var file string

    var line int

    l.mu.Lock()

    defer l.mu.Unlock()

    if l.flag&(Lshortfile|Llongfile) != 0 {

        // Release lock while getting caller info - it's expensive.

        l.mu.Unlock()

        var ok bool

        _, file, line, ok = runtime.Caller(calldepth)

        if !ok {

            file = "???"

            line = 0

        }

        l.mu.Lock()

    }

    l.buf = l.buf[:0]

    l.formatHeader(&l.buf, now, file, line)

    l.buf = append(l.buf, s...)

    if len(s) == 0 || s[len(s)-1] != '\n' {

        l.buf = append(l.buf, '\n')

    }

    _, err := l.out.Write(l.buf)

    return err

}

那这个呢?


func (l *Logger) Output(calldepth int, s string) error {

    now := time.Now() // get this early.

    var file string

    var line int

    if l.flag&(Lshortfile|Llongfile) != 0 {

        var ok bool

        _, file, line, ok = runtime.Caller(calldepth)

        if !ok {

            file = "???"

            line = 0

        }

    }

    // acquire mutex here, avoid aquire mutex twice. 

    l.mu.Lock()

    defer l.mu.Unlock()

    l.buf = l.buf[:0]

    l.formatHeader(&l.buf, now, file, line)

    l.buf = append(l.buf, s...)

    if len(s) == 0 || s[len(s)-1] != '\n' {

        l.buf = append(l.buf, '\n')

    }

    _, err := l.out.Write(l.buf)

    return err

}


大话西游666
浏览 101回答 1
1回答

饮歌长啸

Logger.flag是受互斥体保护的字段,而不是常量。log.Logger有一个SetFlags方法,可以随时从任何 goroutine 调用。该方法实现为:// SetFlags sets the output flags for the logger.// The flag bits are Ldate, Ltime, and so on.func (l *Logger) SetFlags(flag int) {    l.mu.Lock()    defer l.mu.Unlock()    l.flag = flag}文档本身清楚地表明记录器可以安全地并发使用:一个 Logger 可以同时从多个 goroutine 中使用;...为确保这一保证,任何Logger可以修改的字段都必须同步。如果您在l.flag没有正确同步的情况下访问,您将引入竞争条件。
随时随地看视频慕课网APP

相关分类

Go
我要回答