doulei2100
doulei2100
2017-11-08 22:58

Panic()与struct vs指针的含义?

  • IT行业问题
  • 计算机技术
  • it技术
  • 编程语言问答
  • 互联网问答
已采纳

What are the implications, if any, of calling panic(x) with a large struct, versus calling panic(&x) with a pointer to that struct instead?

Does the interface{} that you pass to panic get copied over each time the stack unwinds a level, or is there some other magic going on?

EDIT: An example of where this could be important is inside http.Serve, where it will recover from any panic and serve a suitable message. If I panic with a really large struct, this could have some performance impact as the stack frames unwind and cause undue load to my webserver.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • doumei1203 doumei1203 4年前

    It depends on how many times panics are executed, on value or pointer argument, on the size of the struct, and so on. In Go, arguments are passed by value. Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to a copy of the associated data.

    Use the Go testing package benchmark facilities. For example,

    package main
    
    import "testing"
    
    var sink int
    
    func panic(interface{}) {}
    
    func BenchmarkPanicVal1K(b *testing.B) {
        var large struct{ big [1024]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            panic(large)
        }
    }
    
    func BenchmarkPanicPtr1K(b *testing.B) {
        var large struct{ big [1024]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            panic(&large)
        }
    }
    
    func BenchmarkPanicVal4K(b *testing.B) {
        var large struct{ big [4096]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            panic(large)
        }
    }
    
    func BenchmarkPanicPtr4K(b *testing.B) {
        var large struct{ big [4096]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            panic(&large)
        }
    }
    
    func BenchmarkIfaceVal1K(b *testing.B) {
        var iface interface{}
        var large struct{ big [1024]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            iface = large
        }
        _ = iface
    }
    
    func BenchmarkIfacePtr1K(b *testing.B) {
        var iface interface{}
        var large struct{ big [1024]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            iface = &large
        }
        _ = iface
    }
    func BenchmarkIfaceVal4K(b *testing.B) {
        var iface interface{}
        var large struct{ big [4096]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            iface = large
        }
        _ = iface
    }
    
    func BenchmarkIfacePtr4K(b *testing.B) {
        var iface interface{}
        var large struct{ big [4096]byte }
        b.ReportAllocs()
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
            iface = &large
        }
        _ = iface
    }
    

    Output:

    $ gotest panic_test.go -bench=.
    
    BenchmarkPanicVal1K-4      20000000      70.3 ns/op        0 B/op    0 allocs/op
    BenchmarkPanicPtr1K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op
    BenchmarkPanicVal4K-4       1000000    1483 ns/op       4096 B/op    1 allocs/op
    BenchmarkPanicPtr4K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op
    
    
    BenchmarkIfaceVal1K-4       5000000     378 ns/op       1024 B/op    1 allocs/op
    BenchmarkIfacePtr1K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op
    BenchmarkIfaceVal4K-4       1000000    1469 ns/op       4096 B/op    1 allocs/op
    BenchmarkIfacePtr4K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op
    

    References:

    Go Data Structures: Interfaces

    点赞 评论 复制链接分享

为你推荐