前言

最近简单学了下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

#include <stdio.h>
#include <stdlib.h> 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()

简单对比Java、Python、Go、Rust等常见语言计算斐波拉契数的性能的更多相关文章

  1. 初识python: 斐波拉契数(生成器获取)

    使用  生成器(yield) 获取斐波拉契数. 代码如下: def fun(n): a,b,c = 0,0,1 while a < n: yield b # b, c = c, b + c 以下 ...

  2. 初识python:斐波拉契数(列表获取)

    使用 列表 获取斐波拉契数,代码如下: n = int(input('您想获取前几个斐波拉契数?\n')) li = [] for i in range(n): if i <= 1: li.ap ...

  3. 算法笔记_001:斐波那契数的多种解法(Java)

    本篇文章解决的问题来源于算法设计与分析课程的课堂作业,主要是运用多种方法来计算斐波那契数.具体问题及解法如下: 一.问题1: 问题描述:利用迭代算法寻找不超过编程环境能够支持的最大整数的斐波那契数是第 ...

  4. 用递归方法计算斐波那契数列(Recursion Fibonacci Sequence Python)

    先科普一下什么叫斐波那契数列,以下内容摘自百度百科: 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因意大利数学家列昂纳多·斐波那契(Leonardoda Fibonacci ...

  5. python迭代器实现斐波拉契求值

    斐波那契数列(Fibonacci sequence),又称黄金分割数列,也称为"兔子数列":F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*).例 ...

  6. Java面试题:小白不得不懂的斐波那契数列

    很长一段时间里,我都非常疑惑:“我写的技术文章不差啊,有内容的同时还很有趣,不至于每篇只有区区几十个人读啊?为什么有些内容简单到只有一行注册码的文章浏览量反而轻松破万?”这样的疑惑如鲠在喉啊!写技术博 ...

  7. 实现斐波拉契数列的四种方式python代码

    斐波那契数列 1. 斐波拉契数列简介 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引 ...

  8. java 递归及其经典应用--求阶乘、打印文件信息、计算斐波那契数列

    什么是递归 我先看下百度百科的解释: 一种计算过程,如果其中每一步都要用到前一步或前几步的结果,称为递归的.用递归过程定义的函数,称为递归函数,例如连加.连乘及阶乘等.凡是递归的函数,都是可计算的,即 ...

  9. python学习笔记之斐波拉契数列学习

    著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到: 1, 1, 2, 3, 5, 8, 13, 21, 34, ... 如果用Python的列表生成式, ...

  10. 斐波拉契数列(用JavaScript和Python实现)

    1.用JavaScript 判断斐波拉契数列第n个数是多少 //需求:封装一个函数,求斐波那契数列的第n项 //斐波拉契数列 var n=parseInt(prompt("输入你想知道的斐波 ...

随机推荐

  1. 使用XAG配置GoldenGate在RAC集群环境中的高可用

    背景:本文是根据实际客户测试需求整理,因为客户OGG所在环境只有GI集群,数据库部署在其他位置,所以会有一些差异,但核心思路一致,已完全测试通过,整理出来供大家参考. 1.前期准备 2.创建ACFS文 ...

  2. UVA11573 Ocean Currents

    题目链接 题目 见链接. 题解 知识点:BFS. 这道题显然用BFS,但发现洋流方向会破坏时间的有序性,但注意到洋流时间花费是 \(0\) ,因此只需要用双端队列即可,洋流方向扩展直接放队头,其他方向 ...

  3. linux 中grep 命令详细使用方法说明

    前言在linux命令行中,经常需要对当前获取的一堆数据进行过滤.提取和分析,其中grep命令是其中非常重要的命令之一,比如,在生产环境服务器上,经常使用到下面这个命令 ps -ef | grep ja ...

  4. 【framework】DisplayContent简介

    1 前言 ​ DisplayContent 用于管理屏幕,一块屏幕对应一个 DisplayContent 对象,虽然手机只有一个显示屏,但是可以创建多个 DisplayContent 对象,如投屏时, ...

  5. 探秘SuperCLUE-Safety:为中文大模型打造的多轮对抗安全新框架

    探秘SuperCLUE-Safety:为中文大模型打造的多轮对抗安全新框架 进入2023年以来,ChatGPT的成功带动了国内大模型的快速发展,从通用大模型.垂直领域大模型到Agent智能体等多领域的 ...

  6. Springboot thymeleaf实战总结

    介绍 以下总结了使用Thymeleaf做项目过程中碰到的有价值的知识点.拿出来分享! 1.配置context-path 在公共模板中添加: <script type="text/jav ...

  7. Oracle 中UNDO与REDO的区别详解

    一 为了更清楚的看出2者区别,请看下表: UNDO                                                                   REDO Rec ...

  8. Java I/O 教程(一) 介绍

    Java I/O (Input and Output) 用于处理输入和输出 Java利用流的手段来加快I/O操作.java.io包中包含了各种支持输入输出操作的类.参考下图: 我们可以利用java i ...

  9. 【Android 逆向】【攻防世界】app2

    1. 手机安装apk,随便点击,进入到第二个页面就停了 2. jadx打开apk,发现一共有三个activity,其中第三个activity: FileDataActivity 里面有东西 publi ...

  10. 一个有意思的问题:Kafka的消费Offset会溢出吗

    最近在项目上接入公司APP产品的用户点击日志数据时,发现消费者组的Offset值非常大,才一天的时间,已提交的Offset值就有千亿级别了. 于是不禁想了一个问题:假设一个Topic就只有一个Part ...