为什么 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 在小程序上 非常 也做得很好,但前提是您 运行 测试正确以确保公平比较。
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 在小程序上 非常 也做得很好,但前提是您 运行 测试正确以确保公平比较。