我在谷歌上搜索了一下Go的网站,但我找不到Go非凡的构建时间的解释。它们是语言特性(或缺乏特性)的产物、高度优化的编译器还是其他什么?我并不是在推广围棋;我只是好奇。
当前回答
Go编译器比大多数C/ c++编译器快得多的原因有很多:
Top reason: Most C/C++ compilers exhibit exceptionally bad designs (from compilation speed perspective). Also, from compilation speed perspective, some parts of the C/C++ ecosystem (such as editors in which programmers are writing their code) aren't designed with speed-of-compilation in mind. Top reason: Fast compilation speed was a conscious choice in the Go compiler and also in the Go language The Go compiler has a simpler optimizer than C/C++ compilers Unlike C++, Go has no templates and no inline functions. This means that Go doesn't need to perform any template or function instantiation. The Go compiler generates low-level assembly code sooner and the optimizer works on the assembly code, while in a typical C/C++ compiler the optimization passes work on an internal representation of the original source code. The extra overhead in the C/C++ compiler comes from the fact that the internal representation needs to be generated. Final linking (5l/6l/8l) of a Go program can be slower than linking a C/C++ program, because the Go compiler is going through all of the used assembly code and maybe it is also doing other extra actions that C/C++ linkers aren't doing Some C/C++ compilers (GCC) generate instructions in text form (to be passed to the assembler), while the Go compiler generates instructions in binary form. Extra work (but not much) needs to be done in order to transform the text into binary. The Go compiler targets only a small number of CPU architectures, while the GCC compiler targets a large number of CPUs Compilers which were designed with the goal of high compilation speed, such as Jikes, are fast. On a 2GHz CPU, Jikes can compile 20000+ lines of Java code per second (and the incremental mode of compilation is even more efficient).
其他回答
虽然上面的大部分都是正确的,但有一点非常重要,没有被真正提到:依赖管理。
Go只需要包含您直接导入的包(就像那些已经导入的包一样)。这与C/ c++形成鲜明对比,在C/ c++中,每个文件都包含x头文件,其中包含y头文件等等。总结:Go的编译需要线性时间w.r.t到导入包的数量,而C/ c++需要指数级的时间。
编译的基本思想实际上非常简单。原则上,递归下降解析器可以以I/O限制的速度运行。代码生成基本上是一个非常简单的过程。符号表和基本类型系统并不需要大量的计算。
然而,降低编译器的速度并不难。
如果存在一个预处理器阶段,其中包含多级包含指令、宏定义和条件编译,尽管这些东西很有用,但加载它并不难。(举个例子,我想到了Windows和MFC头文件。)这就是为什么预编译头文件是必要的。
在优化生成的代码方面,可以向该阶段添加多少处理是没有限制的。
我认为不是Go编译器快,而是其他编译器慢。
C和c++编译器必须解析大量的头文件——例如,编译c++“hello world”需要编译18k行代码,这几乎是半兆字节的源代码!
$ cpp hello.cpp | wc
18364 40513 433334
Java和c#编译器在VM中运行,这意味着在它们编译任何东西之前,操作系统必须加载整个VM,然后必须将它们从字节码编译为本机代码,所有这些都需要一些时间。
编译的速度取决于几个因素。
有些语言被设计为快速编译。例如,Pascal被设计为使用单遍编译器进行编译。
编译器本身也可以优化。例如,Turbo Pascal编译器是用手工优化的汇编器编写的,结合语言设计,可以在286类硬件上运行非常快的编译器。我认为即使是现在,现代的Pascal编译器(例如FreePascal)也比Go编译器快。
简单(用我自己的话说),因为语法非常容易(分析和解析)
例如,没有类型继承意味着不需要进行有问题的分析,以确定新类型是否遵循基类型施加的规则。
例如,在这个代码示例:"interfaces"中,编译器在分析该类型时不会去检查预期的类型是否实现了给定的接口。只有在它被使用之前(如果它被使用)才会执行检查。
另一个例子,编译器会告诉你你是否声明了一个变量而没有使用它(或者如果你应该持有一个返回值而你没有)
以下代码不能编译:
package main
func main() {
var a int
a = 0
}
notused.go:3: a declared and not used
这种强制和原则使生成的代码更安全,并且编译器不必执行程序员可以执行的额外验证。
总的来说,所有这些细节使语言更容易解析,从而导致快速编译。
再一次,用我自己的话来说。
围棋的设计就是要快,这一点已经体现出来了。
Dependency Management: no header file, you just need to look at the packages that are directly imported (no need to worry about what they import) thus you have linear dependencies. Grammar: the grammar of the language is simple, thus easily parsed. Although the number of features is reduced, thus the compiler code itself is tight (few paths). No overload allowed: you see a symbol, you know which method it refers to. It's trivially possible to compile Go in parallel because each package can be compiled independently.
请注意,Go并不是唯一具有这些特性的语言(模块是现代语言的标准),但它们做得很好。