Go 戈朗:做切片表演

Go 戈朗:做切片表演,go,Go,为什么这些基准结果如此不同 func Benchmark1(b *testing.B) { for n := 0; n < b.N; n++ { _ = make([]byte, 8) } } func Benchmark2(b *testing.B) { length := 1 for n := 0; n < b.N; n++ { _ = make([]byte, 7+length) } } 常量表达式8在

为什么这些基准结果如此不同

func Benchmark1(b *testing.B) {
    for n := 0; n < b.N; n++ {
        _ = make([]byte, 8)
    }
}

func Benchmark2(b *testing.B) {
    length := 1
    for n := 0; n < b.N; n++ {
        _ = make([]byte, 7+length)
    }
}

常量表达式
8
在编译时计算。
make
在goroutine堆栈上分配(便宜)。变量表达式
7+长度
在运行时计算。
make
在程序堆上分配(昂贵)。如果
make
大小对于堆栈分配来说太大(例如,常量
(64*1024)
和变量
(64*1024-1)+length
),则这两个分配都在堆上进行,基准时间相同

$ go tool compile -m a_test.go
a_test.go:5: Benchmark1 b does not escape
a_test.go:7: Benchmark1 make([]byte, 8) does not escape
a_test.go:14: make([]byte, 7 + length) escapes to heap
a_test.go:11: Benchmark2 b does not escape
$ 
a_测试开始

package a

import "testing"

func Benchmark1(b *testing.B) {
    for n := 0; n < b.N; n++ {
        _ = make([]byte, 8)
    }
}

func Benchmark2(b *testing.B) {
    length := 1
    for n := 0; n < b.N; n++ {
        _ = make([]byte, 7+length)
    }
}
基准1:

"".Benchmark1 t=1 size=112 value=0 args=0x8 locals=0x20
    0x0000 00000 (a_test.go:5)  TEXT    "".Benchmark1(SB), $32-8
    0x0000 00000 (a_test.go:5)  SUBQ    $32, SP
    0x0004 00004 (a_test.go:5)  MOVQ    "".b+40(FP), CX
    0x0009 00009 (a_test.go:5)  FUNCDATA    $0, gclocals·87d20ce1b58390b294df80b886db78bf(SB)
    0x0009 00009 (a_test.go:5)  FUNCDATA    $1, gclocals·790e5cc5051fc0affc980ade09e929ec(SB)
    0x0009 00009 (a_test.go:6)  MOVQ    $0, AX
    0x000b 00011 (a_test.go:6)  NOP
    0x000b 00011 (a_test.go:6)  MOVQ    112(CX), BX
    0x000f 00015 (a_test.go:6)  CMPQ    BX, AX
    0x0012 00018 (a_test.go:6)  JLE $0, 98
    0x0014 00020 (a_test.go:7)  MOVQ    $0, BX
    0x0016 00022 (a_test.go:7)  MOVB    BL, "".autotmp_0001(SP)
    0x0019 00025 (a_test.go:7)  MOVB    BL, "".autotmp_0001+1(SP)
    0x001d 00029 (a_test.go:7)  MOVB    BL, "".autotmp_0001+2(SP)
    0x0021 00033 (a_test.go:7)  MOVB    BL, "".autotmp_0001+3(SP)
    0x0025 00037 (a_test.go:7)  MOVB    BL, "".autotmp_0001+4(SP)
    0x0029 00041 (a_test.go:7)  MOVB    BL, "".autotmp_0001+5(SP)
    0x002d 00045 (a_test.go:7)  MOVB    BL, "".autotmp_0001+6(SP)
    0x0031 00049 (a_test.go:7)  MOVB    BL, "".autotmp_0001+7(SP)
    0x0035 00053 (a_test.go:7)  LEAQ    "".autotmp_0001(SP), BX
    0x0039 00057 (a_test.go:7)  CMPQ    BX, $0
    0x003d 00061 (a_test.go:7)  JEQ $1, 103
    0x003f 00063 (a_test.go:7)  MOVQ    $8, "".autotmp_0002+16(SP)
    0x0048 00072 (a_test.go:7)  MOVQ    $8, "".autotmp_0002+24(SP)
    0x0051 00081 (a_test.go:7)  MOVQ    BX, "".autotmp_0002+8(SP)
    0x0056 00086 (a_test.go:6)  INCQ    AX
    0x0059 00089 (a_test.go:6)  NOP
    0x0059 00089 (a_test.go:6)  MOVQ    112(CX), BX
    0x005d 00093 (a_test.go:6)  CMPQ    BX, AX
    0x0060 00096 (a_test.go:6)  JGT $0, 20
    0x0062 00098 (a_test.go:9)  ADDQ    $32, SP
    0x0066 00102 (a_test.go:9)  RET
    0x0067 00103 (a_test.go:7)  MOVL    AX, (BX)
    0x0069 00105 (a_test.go:7)  JMP 63
基准测试2

"".Benchmark2 t=1 size=144 value=0 args=0x8 locals=0x58
    0x0000 00000 (a_test.go:11) TEXT    "".Benchmark2(SB), $88-8
    0x0000 00000 (a_test.go:11) MOVQ    (TLS), CX
    0x0009 00009 (a_test.go:11) CMPQ    SP, 16(CX)
    0x000d 00013 (a_test.go:11) JLS 129
    0x000f 00015 (a_test.go:11) SUBQ    $88, SP
    0x0013 00019 (a_test.go:11) FUNCDATA    $0, gclocals·87d20ce1b58390b294df80b886db78bf(SB)
    0x0013 00019 (a_test.go:11) FUNCDATA    $1, gclocals·790e5cc5051fc0affc980ade09e929ec(SB)
    0x0013 00019 (a_test.go:12) MOVQ    $1, "".length+56(SP)
    0x001c 00028 (a_test.go:13) MOVQ    $0, AX
    0x001e 00030 (a_test.go:13) MOVQ    "".b+96(FP), BP
    0x0023 00035 (a_test.go:13) NOP
    0x0023 00035 (a_test.go:13) MOVQ    112(BP), BX
    0x0027 00039 (a_test.go:13) MOVQ    AX, "".n+48(SP)
    0x002c 00044 (a_test.go:13) CMPQ    BX, AX
    0x002f 00047 (a_test.go:13) JLE $0, 124
    0x0031 00049 (a_test.go:14) MOVQ    "".length+56(SP), AX
    0x0036 00054 (a_test.go:14) ADDQ    $7, AX
    0x003a 00058 (a_test.go:14) LEAQ    type.[]uint8(SB), BX
    0x0041 00065 (a_test.go:14) MOVQ    BX, (SP)
    0x0045 00069 (a_test.go:14) MOVQ    AX, 8(SP)
    0x004a 00074 (a_test.go:14) MOVQ    AX, 16(SP)
    0x004f 00079 (a_test.go:14) PCDATA  $0, $0
    0x004f 00079 (a_test.go:14) CALL    runtime.makeslice(SB)
    0x0054 00084 (a_test.go:14) MOVQ    24(SP), BX
    0x0059 00089 (a_test.go:14) MOVQ    BX, "".autotmp_0005+64(SP)
    0x005e 00094 (a_test.go:14) MOVQ    32(SP), BX
    0x0063 00099 (a_test.go:14) MOVQ    BX, "".autotmp_0005+72(SP)
    0x0068 00104 (a_test.go:14) MOVQ    40(SP), BX
    0x006d 00109 (a_test.go:14) MOVQ    BX, "".autotmp_0005+80(SP)
    0x0072 00114 (a_test.go:13) MOVQ    "".n+48(SP), AX
    0x0077 00119 (a_test.go:13) INCQ    AX
    0x007a 00122 (a_test.go:13) NOP
    0x007a 00122 (a_test.go:13) JMP 30
    0x007c 00124 (a_test.go:16) ADDQ    $88, SP
    0x0080 00128 (a_test.go:16) RET
    0x0081 00129 (a_test.go:11) CALL    runtime.morestack_noctxt(SB)
    0x0086 00134 (a_test.go:11) JMP 0

这并没有回答您的问题,但描绘了一幅更完整的画面:。由于某些原因,在操场上跑步会产生所有0.00 ns/op。在我的机器上,当长度是一个文字8,常数8,两个文字加起来等于8,或者一个常数和一个文字加起来等于8,它们都差不多,大约1.45 ns/op。当长度是一个变量8,或者一个变量加上一个文字加起来等于8,它们差不多相同,比前一组慢得多,大约91 ns/op。要运行它,请将内容粘贴到一个文件中,然后简单地
运行PATH_To_file
。您知道为什么在第二种情况下,编译器不在
7+长度上执行常量传播并生成相同的代码吗?这只是Go(目前)没有做的事情,还是不能做的事情?@matt:由于
7+length
的值是一个运行时变量表达式,编译器必须进行数据流分析,以证明它对
make([]的唯一值,7+length
是8。如果我们写
const length=1
很容易。如果我们像这里这样写,
var length=1
则更难,更耗时。第一步是SSA编译器:。现在
gc
编译器是用Go编写的,一个用于Go的SSA
gc
编译器正在开发中:。
"".Benchmark1 t=1 size=112 value=0 args=0x8 locals=0x20
    0x0000 00000 (a_test.go:5)  TEXT    "".Benchmark1(SB), $32-8
    0x0000 00000 (a_test.go:5)  SUBQ    $32, SP
    0x0004 00004 (a_test.go:5)  MOVQ    "".b+40(FP), CX
    0x0009 00009 (a_test.go:5)  FUNCDATA    $0, gclocals·87d20ce1b58390b294df80b886db78bf(SB)
    0x0009 00009 (a_test.go:5)  FUNCDATA    $1, gclocals·790e5cc5051fc0affc980ade09e929ec(SB)
    0x0009 00009 (a_test.go:6)  MOVQ    $0, AX
    0x000b 00011 (a_test.go:6)  NOP
    0x000b 00011 (a_test.go:6)  MOVQ    112(CX), BX
    0x000f 00015 (a_test.go:6)  CMPQ    BX, AX
    0x0012 00018 (a_test.go:6)  JLE $0, 98
    0x0014 00020 (a_test.go:7)  MOVQ    $0, BX
    0x0016 00022 (a_test.go:7)  MOVB    BL, "".autotmp_0001(SP)
    0x0019 00025 (a_test.go:7)  MOVB    BL, "".autotmp_0001+1(SP)
    0x001d 00029 (a_test.go:7)  MOVB    BL, "".autotmp_0001+2(SP)
    0x0021 00033 (a_test.go:7)  MOVB    BL, "".autotmp_0001+3(SP)
    0x0025 00037 (a_test.go:7)  MOVB    BL, "".autotmp_0001+4(SP)
    0x0029 00041 (a_test.go:7)  MOVB    BL, "".autotmp_0001+5(SP)
    0x002d 00045 (a_test.go:7)  MOVB    BL, "".autotmp_0001+6(SP)
    0x0031 00049 (a_test.go:7)  MOVB    BL, "".autotmp_0001+7(SP)
    0x0035 00053 (a_test.go:7)  LEAQ    "".autotmp_0001(SP), BX
    0x0039 00057 (a_test.go:7)  CMPQ    BX, $0
    0x003d 00061 (a_test.go:7)  JEQ $1, 103
    0x003f 00063 (a_test.go:7)  MOVQ    $8, "".autotmp_0002+16(SP)
    0x0048 00072 (a_test.go:7)  MOVQ    $8, "".autotmp_0002+24(SP)
    0x0051 00081 (a_test.go:7)  MOVQ    BX, "".autotmp_0002+8(SP)
    0x0056 00086 (a_test.go:6)  INCQ    AX
    0x0059 00089 (a_test.go:6)  NOP
    0x0059 00089 (a_test.go:6)  MOVQ    112(CX), BX
    0x005d 00093 (a_test.go:6)  CMPQ    BX, AX
    0x0060 00096 (a_test.go:6)  JGT $0, 20
    0x0062 00098 (a_test.go:9)  ADDQ    $32, SP
    0x0066 00102 (a_test.go:9)  RET
    0x0067 00103 (a_test.go:7)  MOVL    AX, (BX)
    0x0069 00105 (a_test.go:7)  JMP 63
"".Benchmark2 t=1 size=144 value=0 args=0x8 locals=0x58
    0x0000 00000 (a_test.go:11) TEXT    "".Benchmark2(SB), $88-8
    0x0000 00000 (a_test.go:11) MOVQ    (TLS), CX
    0x0009 00009 (a_test.go:11) CMPQ    SP, 16(CX)
    0x000d 00013 (a_test.go:11) JLS 129
    0x000f 00015 (a_test.go:11) SUBQ    $88, SP
    0x0013 00019 (a_test.go:11) FUNCDATA    $0, gclocals·87d20ce1b58390b294df80b886db78bf(SB)
    0x0013 00019 (a_test.go:11) FUNCDATA    $1, gclocals·790e5cc5051fc0affc980ade09e929ec(SB)
    0x0013 00019 (a_test.go:12) MOVQ    $1, "".length+56(SP)
    0x001c 00028 (a_test.go:13) MOVQ    $0, AX
    0x001e 00030 (a_test.go:13) MOVQ    "".b+96(FP), BP
    0x0023 00035 (a_test.go:13) NOP
    0x0023 00035 (a_test.go:13) MOVQ    112(BP), BX
    0x0027 00039 (a_test.go:13) MOVQ    AX, "".n+48(SP)
    0x002c 00044 (a_test.go:13) CMPQ    BX, AX
    0x002f 00047 (a_test.go:13) JLE $0, 124
    0x0031 00049 (a_test.go:14) MOVQ    "".length+56(SP), AX
    0x0036 00054 (a_test.go:14) ADDQ    $7, AX
    0x003a 00058 (a_test.go:14) LEAQ    type.[]uint8(SB), BX
    0x0041 00065 (a_test.go:14) MOVQ    BX, (SP)
    0x0045 00069 (a_test.go:14) MOVQ    AX, 8(SP)
    0x004a 00074 (a_test.go:14) MOVQ    AX, 16(SP)
    0x004f 00079 (a_test.go:14) PCDATA  $0, $0
    0x004f 00079 (a_test.go:14) CALL    runtime.makeslice(SB)
    0x0054 00084 (a_test.go:14) MOVQ    24(SP), BX
    0x0059 00089 (a_test.go:14) MOVQ    BX, "".autotmp_0005+64(SP)
    0x005e 00094 (a_test.go:14) MOVQ    32(SP), BX
    0x0063 00099 (a_test.go:14) MOVQ    BX, "".autotmp_0005+72(SP)
    0x0068 00104 (a_test.go:14) MOVQ    40(SP), BX
    0x006d 00109 (a_test.go:14) MOVQ    BX, "".autotmp_0005+80(SP)
    0x0072 00114 (a_test.go:13) MOVQ    "".n+48(SP), AX
    0x0077 00119 (a_test.go:13) INCQ    AX
    0x007a 00122 (a_test.go:13) NOP
    0x007a 00122 (a_test.go:13) JMP 30
    0x007c 00124 (a_test.go:16) ADDQ    $88, SP
    0x0080 00128 (a_test.go:16) RET
    0x0081 00129 (a_test.go:11) CALL    runtime.morestack_noctxt(SB)
    0x0086 00134 (a_test.go:11) JMP 0