为什么C构建小程序比Go或D更快?
Go和D宣传拥有速度惊人的编译器。 由于语言本身的现代设计,同时考虑了单通道解析 了解到大部分构建时间都浪费在链接阶段。我想知道为什么gcc在小程序上速度更快 C为什么C构建小程序比Go或D更快?,c,performance,go,build,d,C,Performance,Go,Build,D,Go和D宣传拥有速度惊人的编译器。 由于语言本身的现代设计,同时考虑了单通道解析 了解到大部分构建时间都浪费在链接阶段。我想知道为什么gcc在小程序上速度更快 C #include <stdio.h> int main() { printf("Hello\n"); } $time javac Hello.java 实0m1.500s 用户0m0.031s 系统0m0.031s 运行compiler filename实际上仍然会运行链接器,并且可能会将大量标准库复制到
#include <stdio.h>
int main() {
printf("Hello\n");
}
$time javac Hello.java
实0m1.500s
用户0m0.031s
系统0m0.031s
运行
compiler filename
实际上仍然会运行链接器,并且可能会将大量标准库复制到生成的可执行文件中(尤其是D和Go,默认情况下,它们会静态链接其语言运行时以获得更好的兼容性)
考虑到这个琐碎的世界:
import std.stdio;
void main() { writeln("hello world"); }
让我在我的电脑上为您演示一些计时:
$ time dmd hello.d
real 0m0.204s
user 0m0.177s
sys 0m0.025s
与使用-c
跳过链接步骤不同,这意味着“编译,不链接”:
将第一次运行的时间减少到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
使用printf而不是writeln将其切成两半!我会回到这一点上
为了比较起见,编译+链接:
$ time dmd hello.d
real 0m0.099s
user 0m0.083s
sys 0m0.014s
这让我们了解了正在发生的事情:
- 链接器占用了大量的时间。使用
将其从等式中删除-c
- 解析标准库也需要大量的时间。仅使用C函数而不是D库可以消除这一点,并提供一种更为友好的外观
- 但是,使用stdlib对于了解可伸缩性很重要
一个好的编译器基准测试将比小型程序更希望隔离这些问题并测试可伸缩性。虽然D在小程序上也表现得很好,但如果您正确运行测试以确保公平比较。您运行什么确切的命令来为每个程序计时?公平地说,Go编译器(可能还有D编译器)并不是针对小程序的快速…而速度即使对于小程序也很重要,这是具有大量依赖关系的大型程序的速度,这才是真正的目标。我怀疑这里发生的事情与标准库有关。一行一行地,D编译它们中最快的。但是一个典型的D hello world程序也会从标准库中导入近100000行代码,因此它在相对于C的小型测试中表现不佳(除非您进行补偿,例如调用printf而不是writef以避免D stdlib),但在较大的程序中,速度变得更为明显。(除非你点击了一个未优化的CTFE路径,lol)除了前面的评论:编译非常小的程序不是测量编译时间的有效方法。在这种情况下,加载和初始化编译器的开销远远超过实际编译时间。你应该和一个更大的程序进行比较,编译时间结果会完全不同。GO是在开发过程中设计的,用于与C++程序比较,可以快速地编译程序(谷歌源代码树刻度)。谷歌的软件工程师们的经验驱使Go的创造者们创造了这种语言及其编译方法(和软件包)。我不明白为什么使用D的标准库或包含链接阶段是不公平的
gcc
抛出可执行文件,因此竞争者也应该这样做。有一个快速的编译器很好,但如果整体构建速度很慢,这并不重要。如果C通过做更少的工作而获胜,为什么D要做更多的工作呢?@user2418306,C只在小程序上获胜,这并不重要。在这方面竞争是没有意义的。Go和D是更复杂的语言,运行时更大,因此当大部分构建时间都用于链接运行时时时,它们的速度明显较慢。您还可以进行汇编并缩短C构建时间,但这也是毫无意义的。但是,当您有一个大型项目时,与编译和链接实际应用程序代码相比,链接算不了什么。C/C++可能需要几分钟、几小时(有些需要一整天)来构建where's Go,而D则需要几秒钟。@user2418306了解您正在测量的内容非常重要。的确,100000行D(hello world+stdio.D+依赖项)编译速度比1000行C(hello world+stdio.h)慢。但是如果你把100k行的D和100k行的C进行比较,你就能看到区别。
$ 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
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
import std.stdio;
void main() { writeln("hello world"); }
$ time dmd hello.d
real 0m0.204s
user 0m0.177s
sys 0m0.025s
$ time dmd -c hello.d
real 0m0.054s
user 0m0.048s
sys 0m0.006s
import core.stdc.stdio;
void main() { printf("hello world\n"); }
$ time dmd -c hello.d
real 0m0.017s
user 0m0.015s
sys 0m0.001s
$ time dmd hello.d
real 0m0.099s
user 0m0.083s
sys 0m0.014s