性能测试-Java VS golang VS rust

image.png

声明

本篇测试并非基准测试,相关测试结果仅供参考,如有错误之处还望指出。

环境

JDK版本

openjdk version “19” 2022-09-20

Golang版本

go version go1.19.1

Rust版本

rustc 1.64.0 (a55dd71d5 2022-09-19)

机器

centos7.9.2/16G内存/4核CPU

测试工具

wrk

测试

为了更接近语言的原生性能我们没有使用相关框架进行操作,采用最原始的写法,主要从内存占用、编译速度、并发量、计算速度等几个方面来分析

注意点:

  • 针对与rust我们需要通过开启其优化才能有性能提升--release,普通开发模式下可能比较慢

业务场景:计算密集

执行一百次递归调用计算斐波拉契数时间空间对比
执行100次递归计算斐波拉契数

业务场景:多线程

通过最新的虚拟线程和协程(Rust中没有虚拟线程,直接使用线程)计算斐波拉契数时间空间对比
通过协程执行100个任务递归计算斐波拉契数

业务场景:高并发

使用各种编写的http服务进行压测,通过使用wrk开启8线程500连接进行请求,其数据结构如下

1
2
3
wrk -c500 -t8 -d30s --latency http://147.106.210.183:8000/serial/abcdefghijklmnopqrist
wrk -c500 -t8 -d30s --latency http://147.106.210.183:8001/serial/abcdefghijklmnopqrist
wrk -c500 -t8 -d30s --latency http://147.106.210.183:8001/serial/abcdefghijklmnopqrist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Running 30s test @ http://147.106.210.183:8000/serial/abcdefghijklmnopqrist
8 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 11.34ms 21.70ms 436.09ms 98.97%
Req/Sec 4.08k 794.69 6.63k 84.37%
Latency Distribution
50% 9.46ms
75% 12.30ms
90% 14.94ms
99% 38.12ms
961548 requests in 30.02s, 104.54MB read
Socket errors: connect 0, read 23020, write 48, timeout 0
Requests/sec: 32030.69
Transfer/sec: 3.48MB

cpu 570%
men 394M
jar siez 17M
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Running 30s test @ http://147.106.210.183:8001/serial/abcdefghijklmnopqrist
8 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 13.33ms 9.67ms 106.38ms 62.59%
Req/Sec 3.62k 3.28k 49.52k 91.97%
Latency Distribution
50% 13.46ms
75% 19.77ms
90% 25.06ms
99% 39.45ms
856099 requests in 30.09s, 124.10MB read
Socket errors: connect 0, read 670, write 0, timeout 0
Requests/sec: 28448.40
Transfer/sec: 4.12MB

cpu 422.7%
men 42M
file size 1k
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
wrk -c500 -t8 -d30s --latency http://localhost:8002
Running 30s test @ http://localhost:8002
8 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 8.29ms 7.45ms 133.77ms 85.81%
Req/Sec 5.59k 3.31k 34.53k 79.66%
Latency Distribution
50% 6.35ms
75% 10.89ms
90% 17.23ms
99% 33.15ms
1330208 requests in 30.09s, 164.92MB read
Socket errors: connect 0, read 685, write 0, timeout 0
Requests/sec: 44202.84
Transfer/sec: 5.48MB


cpu 330%
men 19M
file size 3M

总结

  • java:网站后端、微服务应用、工程级别的应用,生态活跃且完整,其弊端是占用资源多,和另外两种相比显得十分臃肿。Java屏蔽了底层的复杂、容易出错的地方(如指针,内存管理等),毋庸置疑生态是三者中最好的,有很多成熟的方案,如果需要快速搭建功能抢占市场用户资源是个不错的选择

  • golang:源于谷歌开源,在kubernetes的加持下受到了广大开发者的喜爱,其编程风格简洁,性能强悍同时也是带有GC的编程语言,是目前高并发、云原生开发的不二之选。

  • rust:适合系统级应用、追求极致性能。rust是最新出的编程语言,其站在其他语言的肩膀上规避了许多问题,它本身是一门系统的编程语言其有自己独特的一套对象生命周期和作用范围管理机制,在编译时就对代码进行检查,强制我们规避可能出现的问题,注重内存安全、避免类似于C/C++发生内存泄露、野指针的问题,但有能达到C/C++的性能。

在现在的环境下微服务开发在容器化的支持下已经可以实现多语言混合开发,需要结合自身实际业务来对其进行选型,不同的场景选用不同的技术带来的收益也会有所差别。

资料

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution{
public static long fibonacci(long n) {
if (n == 1 || n == 0) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
public static void m2() throws InterruptedException {
int cnt = 100;
long max = 40;
new Scanner(System.in).next();
List<Callable<Long>> tasks = new ArrayList<>();
for (int i = 0; i < cnt; i++) tasks.add(() -> fibonacci(max));
long start = System.currentTimeMillis();
Executors.newVirtualThreadPerTaskExecutor().invokeAll(tasks);
long time = System.currentTimeMillis() - start;
System.out.println(String.format("总耗时:%d 毫秒", time));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

func fibonacci(n uint64) uint64 {
if n == 0 || n == 1 {
return 1
}
return fibonacci(n-1) + fibonacci(n-2)
}

func main() {
fmt.Scanln()
fmt.Println("start...")
cnt := 100
max := 40
t := make([]time.Duration,cnt)
for i := 0; i < cnt; i++ {
start := time.Now() // 获取当前时间
fibonacci(uint64(max))
t[i] = time.Since(start)
}
time := time.Duration(0)
for _, v := range t {
time+=v
}
total:=time.Milliseconds()
fmt.Printf("总耗时:%v 毫秒,平均耗时:%v 毫秒", total, total / int64(cnt))
//总耗时:43859 毫秒,平均耗时:438 毫秒
}

func main1() {
fmt.Scanln()
fmt.Println("start...")
cnt := 100
max := uint64(40)
start := time.Now() // 获取当前时间
group:=sync.WaitGroup{}
for i := 0; i < cnt; i++ {
group.Add(1)//添加一个任务
go func() {
defer func() {
group.Done()//完成一个任务
}()
fibonacci(max)
}()
}
group.Wait()//等待所有任务完成
t := time.Since(start)
total:=t.Milliseconds()
fmt.Printf("总耗时:%v 毫秒", total)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
fn fibonacci(n:i64)->i64{
if n==1||n==0 {
return 1;
}
return fibonacci(n-1) + fibonacci(n-2);
}

pub fn main() {
let mut buf = [0];
io::stdin().read(&mut buf).unwrap();
println!("start...");
let cnt :u128 = 100;
let mut time:Vec<u128> = Vec::with_capacity(cnt as usize);
let max = 40;
for _ in 0..cnt {
let now = Instant::now();
fibonacci(max);
time.push(now.elapsed().as_millis());
}
let mut total = 0;
for t in time {
total+=t;
}
println!("总耗时:{} 毫秒,平均耗时:{} 毫秒",total,total/cnt);
//总耗时:109275 毫秒,平均耗时:1092 毫秒
}

pub fn main() {
let mut buf = [0];
io::stdin().read(&mut buf).unwrap();
println!("start...");
let cnt :u128 = 100;
let max :i64 = 40;
let now = Instant::now();
let mut handles = Vec::with_capacity(cnt as usize);
for _ in 0..cnt {
handles.push(thread::spawn(move|| {
fibonacci(max);
}));
}
for handle in handles {
handle.join().unwrap();
}
let spend = now.elapsed().as_millis();
println!("总耗时:{} 毫秒",spend);
}

性能测试-Java VS golang VS rust
https://mikeygithub.github.io/2022/10/18/yuque/性能测试-Java VS golang VS rust/
作者
Mikey
发布于
2022年10月18日
许可协议