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

use*_*306 -4 c performance d build go

Go和D广告宣传拥有令人难以置信的快速编译器.由于语言本身的现代设计,同时考虑了单通道解析.

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

C

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

d

惯用的

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

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

随着黑客

import core.stdc.stdio;
void main() {
    printf("Hello\n");
}
Run Code Online (Sandbox Code Playgroud)
$ 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.")
}
Run Code Online (Sandbox Code Playgroud)
$ 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.");
    }
}
Run Code Online (Sandbox Code Playgroud)
$ time javac Hello.java
real    0m1.500s
user    0m0.031s
sys     0m0.031s

Ada*_*ppe 9

运行compiler filename实际上仍然运行链接器并且可以将大量标准库复制到生成的可执行文件中(尤其是损坏D和Go,默认情况下,它们的语言运行时静态链接以获得更好的兼容性).

鉴于这个琐碎的D hello世界:

import std.stdio;
void main() { writeln("hello world"); }
Run Code Online (Sandbox Code Playgroud)

让我告诉你我电脑上的一些时间:

$ time dmd hello.d

real    0m0.204s
user    0m0.177s
sys     0m0.025s
Run Code Online (Sandbox Code Playgroud)

与跳过链接步骤相比-c,这意味着"编译,不要链接":

$ time dmd -c hello.d

real    0m0.054s
user    0m0.048s
sys     0m0.006s
Run Code Online (Sandbox Code Playgroud)

将时间缩短到第一次运行的大约1/4 - 在这个小程序中,将近3/4的编译时间实际上是链接.

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

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

$ time dmd -c hello.d

real    0m0.017s
user    0m0.015s
sys     0m0.001s
Run Code Online (Sandbox Code Playgroud)

用printf而不是writeln切成两半!我会回到这个.

并且,为了比较,编译+链接:

$ time dmd hello.d

real    0m0.099s
user    0m0.083s
sys     0m0.014s
Run Code Online (Sandbox Code Playgroud)

这让我们知道发生了什么:

  • 链接器占用了很多时间.使用-c将其从等式中移除.

  • 解析标准库也需要很长一段时间.仅使用C函数而不是D lib可以将其删除并提供更多的苹果到苹果的外观.

  • 但是,使用stdlib对于查看可伸缩性很重要.

什么D(我认为,Go,但我不太了解它们)的目的是减少编译中型到大型程序的时间.小程序已经很快 - 等待几分之一秒(或者在较慢的计算机上可能只有一两个,我现在在它上面有一个很好的SSD可以加快速度,在旋转硬盘上运行相同的命令磁盘大约是时间的两倍!)对于小型构建来说并不是什么大问题.

等待几分钟进行大型构建是一个问题.如果我们可以减少到几秒钟,这是一个重大的胜利.

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

因此,构建包括标准库在内的时间是令人印象深刻的.比C hello世界慢(因为C编译器对较小的lib的工作量较少),但是你已经看到了比C++ hello世界更好的优点,每行更慢,而且每次构建都需要做更多的工作(解析) #includes等).

一个好的编译器基准测试会希望隔离这些问题并测试可伸缩性而不是小程序.虽然d确实非常好于小程序太多,如果你运行测试权,保证公平的比较.

  • @ user2418306,C只赢得无论如何都无关紧要的小程序.竞争中没有意义.Go和D是具有大运行时的更复杂的语言,因此当大部分构建时间用于链接运行时时,它们显然较慢.你也可以进行组装并击败C构建时间,但这也毫无意义.但是当你有一个大型项目时,运行时链接与编译和链接实际应用程序代码相比毫无意义.C/C++可能需要几分钟,几小时(有些需要一整天)才能构建Go和D需要几秒钟的时间. (2认同)
  • @ user2418306了解您所测量的内容非常重要.确实,100,000行D(hello world + stdio.d + dependencies)的编译速度慢于1000行C(hello world + stdio.h).但是,如果你比较100k行D到100k行C,那么你可以看到差异. (2认同)