最近突然间想对比下几个语言间的性能,日常使用的是Java,但平时也会用Python,JavaScript,C,Go之类的语言。Java写项目真的也没有什么问题,成熟的生态圈,遇到问题很容易解决。不过写点小东西的时候,还是觉得Python比较好用,不过就是速度慢了点,很早之前写过一个游戏的移植,脚本语言重构真的是个大问题。Go在上家公司的时候也使用过,不过也都是小的测试了,并没有拿来写过完整点的项目。不过语言的简洁性和C的这种传承,还是很有好感,不过在当时重写公司系统时,最后还是用了Java,主要是大部分的对接都有Java的实现。C一直是我研究的语言,虽然实际写东西不多,但是却看了很多相关的书籍,另外最近研究操作系统和学习汇编语言后,对C的认识又有了新的认识,C的厉害地方就是简洁的设计,性能强大,他的诞生就是为写Unix,缺点是实用性不强,另外内存管理,实际上成熟的项目在内存管理上都有自己的框架,所以对于C/C++之类的语言光学习了语言其实并不能做什么,离应用的距离还很远。
回到正题,我实际上想把Go作为业务研究的语言了,虽然脑海中一直印象他的性能不错,但具体表现怎样能,好像我也并不清楚。最后选择对比的语言是Java、Go、C、Rust四个语言,程序都是运行100000000循环,循环内执行冒泡排序。
Java 代码
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
| public class Test { public static void main(String[] args) { long start = System.nanoTime(); int num = 100000000; for (int i = 0; i < num; i++) { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; bubbleSort(arr); } System.out.println(System.nanoTime() - start); }
public static void bubbleSort(int[] arr) { int length = arr.length - 1; for (int i = 0; i < length; i++) { for (int j = 0; j < length - i; j++) { if (arr[j] < arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } }
|
运行时间
Go 代码
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
| package main
import ( "fmt" "time" )
func main() { start := time.Now().UnixNano() const NUM int = 100000000 for i := 0; i < NUM; i++ { arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} bubbleSort(arr) } fmt.Println(time.Now().UnixNano() - start) }
func bubbleSort(arr []int) { for j := 0; j < len(arr)-1; j++ { for k := 0; k < len(arr)-1-j; k++ { if arr[k] < arr[k+1] { arr[k], arr[k+1] = arr[k+1], arr[k] } } } }
|
运行时间
C 代码
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
| #include <stdlib.h> #include <stdio.h> #include <time.h>
#include <sys/time.h> #include <unistd.h>
void bubbleSort(int* array, int length) { for (int i = 0; i < length -1 ; i++) { for(int j=0; j < length -1 -i; j++) { if(array[j] < array[j+1]) { int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } } } }
int main() { struct timeval t_val; gettimeofday(&t_val, NULL); printf("start, now, sec=%ld m_sec=%d \n", t_val.tv_sec, t_val.tv_usec);
for (int i = 0; i < 100000000; i++) { int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int length = sizeof(array)/sizeof(int); bubbleSort(array, length); } struct timeval t_val_end; gettimeofday(&t_val_end, NULL);
struct timeval t_result; timersub(&t_val_end, &t_val, &t_result);
double consume = t_result.tv_sec + (1.0 * t_result.tv_usec)/1000000; printf("end.elapsed time= %fs \n", consume);
return 0; }
|
运行时间
1 2
| start, now, sec=1617327646 m_sec=57219 end.elapsed time= 1.746955s
|
Rust代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| use std::time::Instant;
pub fn bubble_sort<T: Ord>(arr: &mut [T]) { for i in 0..arr.len() { for j in 0..arr.len() - 1 - i { if arr[j] < arr[j + 1] { arr.swap(j, j + 1); } } } }
fn main() { let start = Instant::now();
for _i in 0..100000000 { let mut numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; bubble_sort(&mut numbers); }
println!("time cost: {:?} ms", start.elapsed().as_millis()); println!("time cost: {:?} us", start.elapsed().as_micros()); println!("time cost: {:?} ns", start.elapsed().as_nanos()); }
|
运行时间
1 2 3
| time cost: 1763 ms time cost: 1763298 us time cost: 1763300912 ns
|
Swift 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import Foundation
func bubbleSort<T: Comparable>(with array: inout [T]) -> [T] { for i in 1..<array.count { for j in 0..<array.count-i where array[j] < array[j+1] { array.swapAt(j, j+1) } } return array }
let start = DispatchTime.now() for _ in 0..<10000000 { var intArray = [1, 2, 3, 4, 5, 6, 7, 8, 9] bubbleSort(with: &intArray) } let end = DispatchTime.now() let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds let timeInterval = Double(nanoTime) / 1_000_000_000 print("Time: \(timeInterval) seconds")
|
运行时间
1
| Time: 2.391004642 seconds
|
总结
最早我对比的是Java和C,因为C是在Debug模式下跑的,反而比Java的慢,这个让我无法接受,不应该啊,后来让朋友跑了下,说应该用Release模式,这才反应过来,Release + O3优化后速度一下子就上来了,明显比Java快。Rust和C基本上都有Debug和Release的区分,现在看来Rust和C是一个级别,Java和Go是另一个档次上的同一级别。现在的Java运行默认是解释和编译的混合模式,所以速度上自然也不错,和Java对标的Go数据上来看略微差点,不过考虑到Java的运行时开销,Go其实还是很有诱惑的,后续有可能赶超Java。
企业开发的话用Java依旧最好的选择,个人创业项目的话用Go其实不错。对于Rust和C,不好选择C语法上比较简洁,很多语言特性跟底层更靠近,需要一定底层知识,写操作系统的话,C依旧是首选。Rust呢?个人觉得语法上比较复杂,混杂的语言特性过于多了,既想兼容底层有想高级别的抽象上靠近现代语言,不过这样的情况下依然保持高性能,还是很令人惊讶的。这个不好选,但Rust更充满诱惑,但复杂的语法让人畏惧。
Go语言虽然有C的传承,不过在类型定义上使用后缀的形式跟C语言正好相反,有时还是比较抵触的,另外因为GC的缘故,性能毕竟还是处于应用语言的级别。Rust太复杂,Swift没有用GC是引用计数,速度上比Rust差些,语法上其实跟Rust也差不多,不过作为一个曾经的iOS开发者,虽然Swift在一段时间大家都非常看好,不过最近几年过去了,其实Swift更多还是Oc的一种替代品,并没有突破苹果的范围,服务端也没有掀起什么风浪,Swift终究是Oc的替代品,也正因为此,他也跟苹果生态深度的绑定,成了某种无法脱颖而出的枷锁。
我心中语言其实就是C语言的改良版,内存管理上希望在语言层面上解决,比如用引用计数。语法上不要太加很多的特性,有Go的那样就可以了,但不是Go。不过目前来看是没有的,要不就是自己写一个,也不是没有可能。但实在要是也没有的Go和Rust总还是不错的选择。