dounai1986 2019-02-10 13:29
浏览 54
已采纳

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

I have a logger that works fine, but produces quite some overhead in regard to memory allocation. Below Debug() function is not printing on purpose, because logOutputLevel isn't high enough.

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

Still that method produces quite some allocs when passing values to it. It doesn't produce heavy allocs when passing pointers to it. See the following benchmarks:

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)
    }
}

Produces:

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

Now that's all nice and I'm trying to rework the Debug() method to accept one string and unlimited pointer arguments only. At a later point I would like to 'dereference' all arguments and pass them to fmt.Printf() if the loglevel is high enough.

How can I achieve this? Is there a specific language idiom for "only pointers"? I assume that ...*interface{} means a pointer to an interface{} (and not any values should be a pointer).

  • 写回答

1条回答 默认 最新

  • donglie7778 2019-02-10 14:26
    关注

    The only way to prevent the allocations is to not do them in the first place.

    This is usually done by putting the debug statement in a conditional block before it's evaluated:

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

    Which is how most logging packages handle it. See the glog Verbose type for example.

    You can use build tags to conditionally compile the Debug function, and ignore the arguments altogether. This isn't guaranteed by the language spec to not allocate, but it is an optimization that the compiler could possibly make in the future, if the current performance it acceptable. Using two separate files, you can switch between the Debug implementations at compile time:

    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{}) {}
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 关于URL获取的参数,无法执行二选一查询
  • ¥15 液位控制,当液位超过高限时常开触点59闭合,直到液位低于低限时,断开
  • ¥15 marlin编译错误,如何解决?
  • ¥15 有偿四位数,节约算法和扫描算法
  • ¥15 VUE项目怎么运行,系统打不开
  • ¥50 pointpillars等目标检测算法怎么融合注意力机制
  • ¥20 Vs code Mac系统 PHP Debug调试环境配置
  • ¥60 大一项目课,微信小程序
  • ¥15 求视频摘要youtube和ovp数据集
  • ¥15 在启动roslaunch时出现如下问题