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

报告相同问题?

悬赏问题

  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler