我之前阅读过一篇比较的文章 Swift vs Go vs Python battle,但觉得时间太老了,这是在一年前写的,某种意义上说,一年时间太长了。 因此我决定在我的 Mac 笔记本 (1.7 GHz Intel Core i5) 上重新做这个测试,同时增加了 C++ 的测试。使用 Python 脚本可以很方便的重新测试(Python 比编译型语言要慢 10 倍左右),而对 C++ 是比较公平的。这次测试的版本是:Go 1.5.3, Swift 2.1.1, C++ clang-700.1.81.
我没法确保我的测试时严谨的,micro-benchmarking 也不关心语言本身的生态、工具和可维护性等方面。同时也不会太关注性能。但 micro-benchmarking 就这样。
下面是这几个语言的测试代码:
Go
package main
import "fmt"
func main() {
var sum int64 = 0
for e := 0; e < 200; e++ {
sum = 0
var x[]int64
for i := 0 ; i < 1000000; i++ {
x = append(x, int64(i));
}
var y[]int64
for i := 0 ; i < 1000000-1; i++ {
y = append(y, x[i]+x[i+1]);
}
for i := 0 ; i < 1000000; i += 100 {
sum += y[i];
}
}
fmt.Println(sum);
}
Swift
var sum : Int64 = 0
for e in 0..<200 {
sum = 0
var x : [Int64] = []
for (var i = 0; i < 1000000; i++) {
x.append(Int64(i));
}
var y: [Int64] = []
for (var i = 0; i < 1000000-1; i++) {
y.append(x[i] + x[i+1]);
}
for (var i = 0; i < 1000000; i+=100) {
sum += y[i]
}
}
print(sum)
C++
#include
#include
int main() {
int64_t sum = 0;
for(int e = 0; e < 200; e++) {
sum = 0;
std::vector x;
for(int i = 0; i < 1000000; i++) {
x.push_back(i);
}
std::vector y;
for(int i = 0; i < 1000000-1; i++) {
y.push_back(x[i] + x[i+1]);
}
for (int i = 0; i < 1000000; i += 100) {
sum += y[i];
}
}
std::cout << sum << std::endl;
}
为什么我会使用 int64 来代替 int 呢?在我的 64 位系统中 C++ 的 int 是 32 位的,而 Go 和 Swift 默认是 64 位的,为了公平起见。
好了,接下来战斗开始:
go build -o test-go go/test.go
swiftc -O -o test-swift swift/test.swift
c++ -O3 -o test-c cplusplus/test.cc
GOMAXPROCS=2 time ./test-go
9999010000 4.32 real 5.99 user 0.38 sys
GOMAXPROCS=1 time ./test-go
9999010000 3.93 real 3.89 user 0.05 sys
time ./test-swift
9999010000 3.96 real 2.82 user 1.12 sys
time ./test-c
9999010000 2.37 real 1.74 user 0.62 sys
从这个测试结果中我们能看到什么?对于 Go 语言来说 GOMAXPROCS 增加了测量的开销。正如我们所期望的,这个影响并不大。C++ 还是如预期般的快。事实上,这个性能的差异体现在内存分配和垃圾收集上。
但让我们来试试一个更小的数组,避免内存的分配影响太大。下面的测试条件 e<=2000 (而不是 200) 并且循环迭代次数使用 100k 替换之前的 1m:
go build -o test-go go/test.go
swiftc -O -o test-swift swift/test.swift
c++ -O3 -o test-c cplusplus/test.cc
GOMAXPROCS=2 time ./test-go
99901000 4.40 real 5.65 user 1.10 sys
GOMAXPROCS=1 time ./test-go
99901000 5.06 real 5.07 user 0.83 sys
time ./test-swift
99901000 2.32 real 2.29 user 0.01 sys
time ./test-c
99901000 1.39 real 1.37 user 0.01 sys
现在我们看到了 Go 落后了,可能是因为其依赖于自己的代码生成器。居然比 C 要慢 3 倍之多。而 Swift 使用 LLVM,代码生成器和 C++ 一样。但增加了一些检查和垃圾收集,因此 Swift 性能比 C++ 慢 2 倍。
从这个测试结果中我们能知道什么?
我怀疑如果 Swift 有首类并发支持,那么很多人会选择 Swift 而不是 Go。但我们不能既要求速度又要好的维护性,如果你不在意并发上慢一点点的话,那就选择 Swift。
此外我还有 Erlang,但其基准测试似乎不太适合这个场景。