博客首发于:www.weeco.tech/3d24fbc2337…
为什么做这个实验
近期在公司的一个项目中惊叹于Bash脚本转换为C/C++程序后,再编译生成二进制文件的效率提升比例,突然就有个想法,对比一下不同语言的执行效率呢? 我们就选取最为常见C、C++、Python2、Python3、Go进行对比,看看同样的内容,不同的语言执行效率有多大的差异。 我们这边通过不同编程语言计算100W以内的质数这样一个功能,进行执行效率对比。
实验环境介绍
虚拟机:host-CPU直通 Linux CentOS 7.6 CPU:Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz gcc版本:4.8.5-44 g++版本:4.8.5-44 go版本:1.18.9 Python2版本:2.7.5 Python3版本:3.6.8
源代码及编译指令
如下分别是C、C++、Go、Python3、Python2代码,其中C、C++、Go代码均编译为二进制文件。 编译指令分别为: C:gcc prime_number.c -O3 -o prime_number_c -lm -std=c99 C++:g++ prime_number.cpp -O3 -o prime_number_cpp -lm Go:go build -o prime_number_go prime_number.go
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
bool is_prime(int n) {
if (n < 2) {
return false;
}
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
int main() {
for (int i = 2; i < 1000000; i++) {
if (is_prime(i)) {
printf("%d\n", i);
}
}
return 0;
}
#include <iostream>
#include <cmath>
using namespace std;
bool is_prime(int n) {
if (n < 2) {
return false;
}
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
int main() {
for (int i = 2; i < 1000000; i++) {
if (is_prime(i)) {
cout << i << endl;
}
}
return 0;
}
package main
import (
"fmt"
"math"
)
func isPrime(n int) bool {
if n < 2 {
return false
}
for i := 2; i <= int(math.Sqrt(float64(n))); i++ {
if n%i == 0 {
return false
}
}
return true
}
func main() {
for i := 2; i < 1000000; i++ {
if isPrime(i) {
fmt.Println(i)
}
}
}
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
for i in range(2, 1000000):
if is_prime(i):
print(i)
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
for i in range(2, 1000000):
if is_prime(i):
print i
对比方式
通过/bin/time -vvv [command] > [file],同时对比C/C++/Go语言编译生成的二进制文件,Python2/3输出的结果是否一致,以及不同语言执行所需的时间。
/bin/time -vvv ./prime_number_c > /tmp/prime_number_c.log
/bin/time -vvv ./prime_number_cpp > /tmp/prime_number_cpp.log
/bin/time -vvv ./prime_number_go > /tmp/prime_number_go.log
/bin/time -vvv python2 prime_number_py2.py > /tmp/prime_number_py2.log
/bin/time -vvv python2 prime_number_py3.py > /tmp/prime_number_py3.log
对比结果
通过以上5条指令,得到5种编程语言的执行结果,通过计算各结果的MD5值,可知其结果一致。
c13929ee9d2aea8f83aa076236079e94 prime_number_c.log
c13929ee9d2aea8f83aa076236079e94 prime_number_cpp.log
c13929ee9d2aea8f83aa076236079e94 prime_number_go.log
c13929ee9d2aea8f83aa076236079e94 prime_number_py2.log
c13929ee9d2aea8f83aa076236079e94 prime_number_py3.log
以User time和System Time总和,即最终的墙上时间作为执行时间进行对比,各编程语言执行时间分别为:
- C:0.16+0.00=0.16秒
- C++:0.15+0.02=0.17秒
- Go:0.50+0.01=0.51秒
- Python2:5.62+0.00=5.62秒
- Python3:5.57+0.01=5.58秒
根据各编程语言的执行时间,绘制了一张图,能够更明显地看出各语言的性能差异:
结论
从数据可以很明显看出,Python2/3的执行时间时间远远高于其他三者,大约是C/C++执行时间的35倍;C/C++的执行时间在误差允许范围内可认为是一致的。同样是编译成二进制,Go编译出来的二进制文件,其执行效率约为C/C++的1/3,当然可能与其编译参数有关。
我们能做什么
既然我们知道这三者的性能差异,那么在对性能有要求的场景下,我们应该尽可能选用C/C++编写,其次选择Go语言。 如果系统整体是用Python完成的,对于其中的高频调用子函数,可以考虑将其转换为C/C++或者Go语言,然后通过二进制调用的方式合入系统中。
这个实验还有后续吗
在这个实验当中,我们对比了不同编程语言C/C++/Go/Python2/Python3的执行效率,很明显,Python2和Python3的效率远低于其他几者,那么是否存在一些优化手段、优化工具,能够提升Python代码的执行效率呢? 留个悬念,下个博客见~