为什么 C 比 Go 或 D 更快地构建小程序?

Why C builds small programs faster than Go or D?

Go 和 D 宣称拥有非常快的编译器。 由于语言本身的现代设计考虑了并发单程解析。

了解大部分构建时间浪费在链接阶段。我想知道为什么 gcc 在小程序上仍然更快。

C

#include <stdio.h>    
int main() {
    printf("Hello\n");
}
$ time gcc hello.c
real    0m0.724s
user    0m0.030s
sys     0m0.046s

D

地道

import std.stdio;
void main() {
    writeln("Hello\n");
}
$ time dmd hello.d

real    0m1.620s
user    0m0.047s
sys     0m0.015s

有技巧

import core.stdc.stdio;
void main() {
    printf("Hello\n");
}
$ time dmd hello.d
real    0m1.593s
user    0m0.061s
sys     0m0.000s

$ time dmd -c hello.d
real    0m1.203s
user    0m0.030s
sys     0m0.031s

package main
import "fmt"
func main() {
    fmt.Println("Hello.")
}
$ time go build hello.go
real    0m2.109s
user    0m0.016s
sys     0m0.031s

Java

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello.");
    }
}
$ time javac Hello.java
real    0m1.500s
user    0m0.031s
sys     0m0.031s

运行 compiler filename 实际上仍然是 运行 的 linker 并且可能会复制大量的标准库到生成的可执行文件中(尤其是伤害 D 和Go,which static link 他们的语言默认 运行 次以获得更好的兼容性)。

鉴于这个微不足道的 D 你好世界:

import std.stdio;
void main() { writeln("hello world"); }

让我在我的电脑上给你看一些时间:

$ time dmd hello.d

real    0m0.204s
user    0m0.177s
sys     0m0.025s

对比跳过 link 步骤 -c,这意味着 "compile, do not link":

$ time dmd -c hello.d

real    0m0.054s
user    0m0.048s
sys     0m0.006s

将时间减少到第一个的 1/4 左右 运行 - 在这个小程序中,近 3/4 的编译时间实际上是 linking.

现在,让我稍微修改一下程序:

import core.stdc.stdio;
void main() { printf("hello world\n"); }

$ time dmd -c hello.d

real    0m0.017s
user    0m0.015s
sys     0m0.001s

使用 printf 代替 writeln 减半!我会回到这个。

并且,为了比较,compile+link:

$ time dmd hello.d

real    0m0.099s
user    0m0.083s
sys     0m0.014s

这让我们了解了正在发生的事情:

  • link 人吃了不少时间。使用 -c 将其从等式中删除。

  • 解析标准库也需要大量时间。仅使用 C 函数而不是 D 库可以消除这种情况,并提供更加统一的外观。

  • 但是,使用标准库对于查看可伸缩性很重要。

D(我猜是 Go,但我对它们了解不多)的目的是减少编译大中型程序的时间。小程序已经很快 - 等待几分之一秒(或者在较慢的计算机上可能需要等待一两秒,我现在使用的那个有一个很好的 SSD 可以加快速度,运行ning 同样在旋转的硬盘上执行命令大约需要两倍的时间!)对于小型构建来说没什么大不了的。

等待几个 分钟 进行大型构建是一个问题。如果我们可以将其缩短到几秒钟,那就是一个重大胜利。

编译 100,000 行的时间比编译 10 行的时间更重要。所以初始化时间并不重要。 Link 时间很重要,但编译器本身并没有做太多(linker 是一个由不同团队编写的单独程序,尽管其他地方也在努力改进它)。

因此,D 构建包括标准库在内的时间令人印象深刻。比 C hello world 慢(因为 C 编译器对较小的 lib 做的工作更少),但是你已经看到了 C++ hello world 的好处,它每行速度更慢,并且在每次构建时往往有更多的工作要做(解析#includes 等)。

一个好的编译器基准比小程序更希望隔离这些问题并测试可伸缩性。尽管 D 在小程序上 非常 也做得很好,但前提是您 运行 测试正确以确保公平比较。