解释一下执行时间差

Explain me the execution time difference

我已经通过 Donovan-Kernighan "The Go Programming Language" 的书开始学习 Golang。在第 1 章中,作者建议测试几个可供选择的简单回声函数实现。我使用 time 函数来计算执行时间,如下所示:

  29 func main() {
  30     var start, end int64
  31     //fmt.Println("Testing echo implementation")
  32     start = time.Now().UTC().UnixNano()
  33     echo3()
  34     end = time.Now().UTC().UnixNano()
  35     fmt.Println(end - start)
  36     start = time.Now().UTC().UnixNano()
  37     echo3()
  38     end = time.Now().UTC().UnixNano()
  39     fmt.Println(end - start)
  40 }

如果我使用 go build ... 命令构建代码,我会得到结果:

➜  go-hello-world ./echo2
./echo2
81073
./echo2
5591

如您所见,第一次调用需要的时间是第二次调用的十倍。请注意,我在这两种情况下都调用了相同的 echo3 函数。我猜 fmt.Println 的第一次调用需要很长时间。为此,我在第 31 行添加了函数调用并再次测试:

➜  go-hello-world ./echo2
Testing echo implementation
./echo2
6327
./echo2
4249

你可以看到两个调用需要的时间差不多。

可是哪里有真相呢?

另一个有趣的时刻是,当我通过 go run ... 命令 运行 我的代码时,我得到的时间要少得多:

➜  go-hello-world go run echo2.go
Testing echo implementation
/tmp/go-build040243191/b001/exe/echo2
1743
/tmp/go-build040243191/b001/exe/echo2
1133
➜  go-hello-world go run echo2.go
/tmp/go-build646239204/b001/exe/echo2
34525
/tmp/go-build646239204/b001/exe/echo2
1133

我想当我用构建命令制作二进制文件时,我可以获得更有效的机器代码来执行。 你能解释一下为什么它在实践中以这种方式工作吗?

环境:

OS: ArchLinux 5.2.5-arch1-1-ARCH
Go: go1.12.7 linux/amd64

P.S。对不起我的英语。

UPD#1

echo3代码:

  20 func echo3() {
  21     s, sep := "", ""
  22     for _, arg := range os.Args[:] {
  23         s += sep + arg
  24         sep = " "
  25     }
  26     fmt.Println(s)
  27 }

UPD#2

➜  go-hello-world go run echo2.go
/tmp/go-build573021176/b001/exe/echo2
13019
/tmp/go-build573021176/b001/exe/echo2
1067
/tmp/go-build573021176/b001/exe/echo2
955
/tmp/go-build573021176/b001/exe/echo2
987

➜  go-hello-world ./echo2          
./echo2
199681
./echo2
19404
./echo2
5965
./echo2
4803
./echo2
4673
./echo2
8244

尝试使用第 11.4 节中所示的基准测试技术编写一个循环 运行 每个方法几百次左右的基准测试方法。

运行之间的差异可能是由多任务操作系统和计时器分辨率等引起的各种测量错误。

另外,我认为当你走得更远的时候再回去做练习是可以的(练习需要对主题有一定的了解)