... interface {}函数参数中的“取消引用”元素

时间:2019-02-10 13:29:05

标签: go

我有一个工作正常的记录器,但在内存分配方面产生了相当大的开销。 Debug()下面的功能不是有意打印的,因为logOutputLevel不够高。

var logOutputLevel = 2
func Debug(s string, args ...interface{}) {
    if logOutputLevel > 1 { return }
    fmt.Printf(s, args...)
}

仍然,该方法在将值传递给它时会产生很多分配。将指针传递给它时,它不会产生繁重的分配。请参阅以下基准:

func BenchmarkLog(b *testing.B) {
    x := "abc"
    for n := 0; n < b.N; n++ {
        Debug("test %s", x)
    }
}

func BenchmarkLogRef(b *testing.B) {
    x := "abc"
    for n := 0; n < b.N; n++ {
        Debug("test %s", &x)
    }
}

产生:

BenchmarkLog-8          50000000            43.1 ns/op        16 B/op          1 allocs/op
BenchmarkLogRef-8       500000000            3.17 ns/op        0 B/op          0 allocs/op

现在一切都很好,我正尝试重新设计Debug()方法,使其仅接受一个字符串和无限的指针参数。稍后,如果日志级别足够高,我想“取消引用”所有参数并将它们传递给fmt.Printf()

我该如何实现?是否有针对“仅指针”的特定语言习语?我假设...*interface{}是指向interface{}的指针(并非任何值都应该是指针)。

1 个答案:

答案 0 :(得分:1)

防止分配的唯一方法是首先不要进行分配。

这通常是通过在评估之前将debug语句放在条件块中来完成的:

if logOutputLevel > 1 {
    Debug("test: %s", x)
}

大多数日志记录程序包将如何处理它。例如,请参见glog Verbose type

您可以使用构建标记有条件地编译Debug函数,而完全忽略参数。语言规范不能保证不分配这种情况,但是如果当前的性能可以接受,这是编译器将来可能会进行的优化。使用两个单独的文件,您可以在编译时在Debug实现之间进行切换:

debug.go

// +build debug

package main

import "log"

func Debug(fmt string, args ...interface{}) {
    log.Printf(fmt, args...)
}

release.go

// +build !debug

package main

func Debug(_ string, _ ...interface{}) {}