前言
最近简单学了下Rust,以我这种菜鸟水平,没感受到什么安全、性能什么方面的优势,只觉得概念太多,编译各种报错。暂时也写不出来什么玩法,索性对比下各种学过的语言的性能。部分语言很早之前学过,很久不用就忘了,所以是用GPT写的。但运行逻辑很简单,所以应该没什么影响。具体的代码可以见“实验代码”部分。
对比方法是在同一台机器上计算斐波拉契数,获取运行时长和内存占用。对比方法很野鸡,看看当个乐就行。
根据个人工作经验来说,大部分业务场景性能只要够用就行,能尽快下班的语言就是好语言。
实验准备
- 测试主机:虚拟机
- 系统:Debian 12.5 x86_64
- CPU:4 核
- 内存:4 GB
使用time
命令计算运行时长和内存消耗。示例,计算C二进制程序的运行时长和内存
/usr/bin/time -f 'Elapsed Time: %e s Max RSS: %M kbytes' ./fib-c 45 # 输出结果 The 45th Fibonacci number is 1134903170 Elapsed Time: 8.36 s Max RSS: 1444 kbytes
部分语言需要编译,二进制文件和代码如下,C编译出来的二进制文件只有16KB。
-rwxr-xr-x 1 atlas atlas 16K Mar 16 16:21 fib-c # C编译的二进制文件 -rwxr-xr-x 1 atlas atlas 1.8M Mar 16 15:56 fib-go # Go编译的二进制文件 -rwxr-xr-x 1 atlas atlas 7.7M Mar 16 17:47 fib-graalvm # GraalVM编译的二进制文件 -rw-r--r-- 1 atlas atlas 175 Mar 16 18:06 fib-js.js # JavaScipt源代码文件 -rw-r--r-- 1 atlas atlas 643 Mar 16 16:48 fib-lua.lua # lua 代码文件 -rw-r--r-- 1 atlas atlas 377 Mar 16 16:49 fib-lua.luac # LuaJIT编译文件 -rw-r--r-- 1 atlas atlas 981 Mar 16 19:17 Fibonacci.class # javac编译文件 -rw-r--r-- 1 atlas atlas 622 Mar 16 17:18 Fibonacci.java # Java源代码文件 -rw-r--r-- 1 atlas atlas 322 Mar 16 16:31 fib-python.py # python源代码文件 -rwxr-xr-x 1 atlas atlas 3.7M Mar 16 15:56 fib-rust # rust编译的二进制文件
实验结果
递归计算数值 45 的斐波拉契数,确保计算出来的值都是1134903170。
根据结果数据来看,Java(OpenJDK)计算最快,但内存占用相当高,接近rust运行内存的20倍。换成GraalVM编译后,内存占用会少很多,但还是比Rust和C要多。
C的内存占用最低,Rust和C基本齐平,二者运行时长也差不多。
Python最慢,意料之中。。但Python平常个人写的也很多,开发速度相当快。
Go平常也经常写,速度和内存占用都尚可,语法也很简单。写习惯了Go的并发语法,再写其它语言就有点感觉怪怪的。
Lua使用本身的解释器运行是很慢的,用luajit编译后效率提升很多。
JS并不熟,完全用GPT给的测试方案。运行速度还行,就是内存占用比Java都高。貌似也有其它js运行时,可能性能比nodejs要好。
语言 | 版本 | 运行时长(seconds) | 环比Rust(越低越好) | 最大内存占用(kbytes) | 环比Rust(越低越好) |
Java | OpenJDK 17.0.2 | 2.75 | -69.7% | 38056 | +1932.9% |
Java | GraalVM 21.0.2+13.1 | 4.37 | -51.8% | 6980 | +272.9% |
Python | 3.11.2 | 112.13 | +1136.3% | 9364 | +400.2% |
Go | 1.21.6 | 4.88 | -46.2% | 3396 | +81.4% |
C | gcc 12.2.0 | 8.36 | -7.8% | 1444 | -22.9% |
Rust | 1.76.0 | 9.07 | 0 | 1872 | 0 |
Lua | Lua 5.4 | 74.22 | +718.3% | 2668 | +42.5% |
Lua | LuaJIT 2.1.0-beta3 | 17.09 | +88.42% | 2296 | +22.6% |
Nodejs | v20.10.0 | 9.18 | +1.2% | 45248 | +2317.1% |
实验代码
Java
public class Fibonacci { public static int fib(int n) { if (n <= 2) { return 1; } return fib(n - 2) + fib(n - 1); } public static void main(String[] args) { if (args.length < 1) { System.out.println("Usage: java Fibonacci NUMBER"); return; } try { int num = Integer.parseInt(args[0]); System.out.println(String.format("The %dth Fibonacci number is %d", num, fib(num))); } catch (NumberFormatException e) { System.out.println("Invalid number provided."); } } }
Python
import sys def fib(n: int) -> int: if n <= 2: return 1 return fib(n-2) + fib(n-1) def main(): if len(sys.argv) < 2: print("Usage: python fib-python.py NUMBER") return print(f"The {sys.argv[1]}th Fibonacci number is {fib(int(sys.argv[1]))}") if __name__ == "__main__": main()
Go
package main import ( "fmt" "os" "strconv" ) func fib(n uint) uint { switch n { case 0: return 0 case 1: return 1 case 2: return 1 default: return (fib(n-2) + fib(n-1)) } } func main() { args := os.Args for i := 1; i < len(args); i++ { v1, err := strconv.Atoi(args[i]) if err != nil { panic(err) } var arg uint = uint(v1) fmt.Printf("The %dth Fibonacci number is %d\n", arg, fib(arg)) } }
Rust
use std::str::FromStr; use std::env; fn fib(n: u64) -> u64 { match n { 0 => 0, 1 => 1, 2 => 1, _ => fib(n - 1) + fib(n - 2), } } fn main() { let mut args = Vec::new(); for arg in env::args().skip(1) { args.push(u64::from_str(&arg).expect("error parsing argument")); } if args.len() == 0 { eprintln!("Usage: fib <number>"); std::process::exit(1); } println!("The {}th Fibonacci number is {}", args[0], fib(args[0])); }
JavaScript
function fib(n) { if (n <= 2) { return 1; } return fib(n - 2) + fib(n - 1); } function main(n) { console.log(`The ${n}th Fibonacci number is ${fib(n)}`); } main(45);
C
long long fibonacci(int n); int main(int argc, char *argv[]) { if (argc != 2) { printf("使用方法: ./fib-c NUMBER\n"); return 1; } int n = atoi(argv[1]); printf("The %dth Fibonacci number is %d\n", n, fibonacci(n)); return 0; } long long fibonacci(int n) { if (n <= 1) return n; else return fibonacci(n - 1) + fibonacci(n - 2); }
Lua
function fib(n) if n <= 2 then return 1 else return fib(n - 2) + fib(n - 1) end end function main() if #arg == 0 then print("Usage: lua fib-lua.lua NUMBER") return end local num = tonumber(arg[1]) if num then print(string.format("The %dth Fibonacci number is %d", num, fib(num))) else print("Invalid number provided.") end end main()