Sivo 悉见

各种编程语言性能测试代码

匿名 · 更新于 2021/10/28

1、test.c (C)

 


#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
int main(int argc, char **argv) {
    int element = 0;
    int iteration = 0;
    int iterations = 0;
    int innerloop = 0;
    double sum = 0.0;
    int array_length = 100000000;
    double *array = (double*)malloc(array_length * sizeof(double));
    if (argc > 1)
        iterations = atoi(argv[1]);
    printf("iterations %d\n", iterations);
    for (element = 0; element < array_length; element++)
        array[element] = element;
    for (iteration = 0; iteration < iterations; iteration++)
        for (innerloop = 0; innerloop < 1000000000; innerloop++)
            sum += array[(iteration + innerloop) % array_length];
    printf("sum %E\n", sum);
    free(array);
    array = NULL;
    return 0;
}

 

2、test.cpp (C++)

 

#include <iostream>
#include <cstdlib>
using namespace std;
int main(int argc, char **argv) {
    int element = 0;
    int iteration = 0;
    int iterations = 0;
    int innerloop = 0;
    double sum = 0;
    int array_length = 100000000;
    double *array = new double[array_length];
    if (argc > 1)
        iterations = atoi(argv[1]);
    cout << "iterations " << iterations << endl;;
    for (element = 0; element < array_length; element++)
        array[element] = element;
    for (iteration = 0; iteration < iterations; iteration++)
        for (innerloop = 0; innerloop < 1000000000; innerloop++)
            sum += array[(iteration + innerloop) % array_length];
    cout << "sum " << sum << endl;
    delete array;
    array = NULL;
    return 0;
}

 

3、test.java (Java):

 


public class test {
    public static void main(String[] args) {
        int element = 0;
        int iteration = 0;
        int iterations = 0;
        int innerloop = 0;
        double sum = 0.0;
        int array_length = 100000000;
        double[] array = new double[array_length];
        if (args.length > 0)
            iterations = Integer.parseInt(args[0]);
        System.out.println("iterations " + iterations);
        for (element = 0; element < array_length; element++)
            array[element] = element;
        for (iteration = 0; iteration < iterations; iteration++)
            for (innerloop = 0; innerloop < 1000000000; innerloop++)
                sum += array[(iteration + innerloop) % array_length];
        System.out.println("sum " + sum);
        array = null;
    }
}

这个Java代码可以编译和执行两种不同的方式。它可以用gcj本地编译,然后直接执行。或者可以用Javac编译成字节码,然后使用Java在Java虚拟机(JVM)中执行。

 

4、Ada

 

test.adb (Ada)
with Ada.Text_IO, Ada.Command_Line, Ada.Unchecked_Deallocation;
use Ada.Text_IO, Ada.Command_Line;
procedure test is
    element : Integer := 0;
    iteration : Integer := 0;
    iterations : Integer := 0;
    innerloop : Integer := 0;
    sum : Standard.Long_Float := 0.0;
    array_length : Integer := 100000000;
    type vector is array (0..array_length) of Standard.Long_Float;
    type vector_access is access vector;
    procedure free_vector is new Ada.Unchecked_Deallocation
        (Object => vector, Name => vector_access);
begin
    declare
        test_array : vector_access := new vector;
    begin
        if Argument_Count > 0 then
            iterations := Integer'Value(Argument(1));
        end if;
        Put_Line("iterations " & Integer'Image(iterations));
        while element < array_length loop
            test_array(element) := Standard.Long_Float(element);
            element := element + 1;
        end loop;
        while iteration < iterations loop
            innerloop := 0;
            while innerloop < 1000000000 loop
                sum := sum + test_array((iteration + innerloop) mod array_length);
                innerloop := innerloop + 1;
            end loop;
            iteration := iteration + 1;
        end loop;
        Put_Line("sum " & Standard.Long_Float'Image(sum));
        free_vector(test_array);
    end;
end test;

 

5、test.go (Go)

 


package main
import "os"
import "fmt"
import "strconv"
func main() {
    var (
        element int = 0
        iteration int = 0
        iterations int = 0
        innerloop int = 0
        sum float64 = 0.0
        array_length int = 100000000
        array []float64 = make([]float64, array_length)
    )
    if len(os.Args) > 1 {
        iterations,_ = strconv.Atoi(os.Args[1])
    }
    fmt.Printf("iterations %d\n", iterations)
    for element = 0; element < array_length; element++ {
        array[element] = float64(element)
    }
    for iteration = 0; iteration < iterations; iteration++ {
        for innerloop = 0; innerloop < 1000000000; innerloop++ {
            sum += array[(iteration + innerloop) % array_length]
        }
    }
    fmt.Printf("sum %E\n", sum)
    array = nil
}

 

6、Python

 

test-python.py (Python)

import sys
import test_python
iterations = 0
if len(sys.argv) > 1:
    iterations = int(sys.argv[1])
test_python.test_python(iterations)

test_python.py (Python)

import sys
def test_python(iterations):
    element = 0
    iteration = 0
    innerloop = 0
    total = float(0.0)
    array_length = 100000000
    array = [i for i in range(array_length)]
    print 'iterations', iterations
    while iteration < iterations:
        innerloop = 0
        while innerloop < 1000000000:
            total += array[(iteration + innerloop) % array_length];
            innerloop += 1
        iteration += 1
    print 'sum', total
    del array

python通常将.py文件编译成.pyc文件,这些文件是在python虚拟机(pvm)中运行的字节码文件。在python或numpy中,似乎没有任何哑数组的概念,也没有一个内存块具有相邻值。python数组和numpy数组似乎是在幕后使用某种链接列表和面向对象的方法来实现的,这可能是性能不佳的原因。

Python w/ Cython Compile

test-python-cython.py (Python)

import sys
import test_python_cython
iterations = 0
if len(sys.argv) > 1:
    iterations = int(sys.argv[1])
test_python_cython.test_python(iterations)

test_python_cython.pyx (Python)

import sys
def test_python(iterations):
    element = 0
    iteration = 0
    innerloop = 0
    total = float(0.0)
    array_length = 100000000
    array = [i for i in range(array_length)]
    print 'iterations', iterations
    while iteration < iterations:
        innerloop = 0
        while innerloop < 1000000000:
            total += array[(iteration + innerloop) % array_length];
            innerloop += 1
        iteration += 1
    print 'sum', total
    del array

setup_python_cython.py (Python)

from distutils.core import setup
from Cython.Build import cythonize
setup(name = 'test python cython', ext_modules = cythonize("test_python_cython.pyx"))

NumPy参考文档中写的很好,它描述了如何从Python获得最佳性能:“那些想要从其低级操作中获得良好性能的人应该强烈地考虑直接使用C中提供的迭代API,但是对于那些不适应C或C++的人来说,Cython是一个很好的中间层。有了合理的性能权衡。”基本上,当性能很重要时,使用C而不是python。Cython将Python源代码转换为c,然后将其本机编译为共享库;然后,Python程序的其余部分可以调用共享库。这种方法导致解释/PVM和本机编译代码的混合。

这里我没有将任何代码更改为C或Cython特定的代码,因为我仍在测试Python。.pyx编译最终比解释的/PVM.py/.pyc文件中相同的python代码运行得更快,但速度仍然很慢。

NumPy

test-numpy.py (Python)

import sys
import test_numpy
iterations = 0
if len(sys.argv) > 1:
    iterations = int(sys.argv[1])
test_numpy.test_python(iterations)

test_numpy.py (Python)

import numpy
import sys
def test_python(iterations):
    element = 0
    iteration = 0
    innerloop = 0
    total = numpy.float64(0.0)
    array_length = 100000000
    array = numpy.zeros(array_length, numpy.float64)
    print 'iterations', iterations
    while element < array_length:
        array[element] = element
        element += 1
    while iteration < iterations:
        innerloop = 0
        while innerloop < 1000000000:
            total += array[(iteration + innerloop) % array_length];
            innerloop += 1
        iteration += 1
    print 'sum', total
    del array

NumPy w/ Cython Compile

test-python-cython.py (Python)

import sys
import test_python_cython
iterations = 0
if len(sys.argv) > 1:
    iterations = int(sys.argv[1])
test_python_cython.test_python(iterations)

test_python_cython.pyx (Python)

import sys
def test_python(iterations):
    element = 0
    iteration = 0
    innerloop = 0
    total = float(0.0)
    array_length = 100000000
    array = [i for i in range(array_length)]
    print 'iterations', iterations
    while iteration < iterations:
        innerloop = 0
        while innerloop < 1000000000:
            total += array[(iteration + innerloop) % array_length];
            innerloop += 1
        iteration += 1
    print 'sum', total
    del array

setup_python_cython.py (Python)

from distutils.core import setup
from Cython.Build import cythonize
setup(name = 'test python cython', ext_modules = cythonize("test_python_cython.pyx"))

NumPy

test-numpy.py (Python)

import sys
import test_numpy
iterations = 0
if len(sys.argv) > 1:
    iterations = int(sys.argv[1])
test_numpy.test_python(iterations)

test_numpy.py (Python)

import numpy
import sys
def test_python(iterations):
    element = 0
    iteration = 0
    innerloop = 0
    total = numpy.float64(0.0)
    array_length = 100000000
    array = numpy.zeros(array_length, numpy.float64)
    print 'iterations', iterations
    while element < array_length:
        array[element] = element
        element += 1
    while iteration < iterations:
        innerloop = 0
        while innerloop < 1000000000:
            total += array[(iteration + innerloop) % array_length];
            innerloop += 1
        iteration += 1
    print 'sum', total
    del array

NumPy w/ Cython Compile

test-numpy-cython.py (Python)

import sys
import test_numpy_cython
iterations = 0
if len(sys.argv) > 1:
    iterations = int(sys.argv[1])
test_numpy_cython.test_python(iterations)

test_numpy_cython.pyx (Python)

import numpy
import sys
def test_python(iterations):
    element = 0
    iteration = 0
    innerloop = 0
    total = numpy.float64(0.0)
    array_length = 100000000
    array = numpy.zeros(array_length, numpy.float64)
    print 'iterations', iterations
    while element < array_length:
        array[element] = element
        element += 1
    while iteration < iterations:
        innerloop = 0
        while innerloop < 1000000000:
            total += array[(iteration + innerloop) % array_length];
            innerloop += 1
        iteration += 1
    print 'sum', total
    del array

 

setup_numpy_cython.py (Python)

from distutils.core import setup
from Cython.Build import cythonize
setup(name = 'test numpy cython', ext_modules = cythonize("test_numpy_cython.pyx"))

Cython w/ Cython Compile

test-cython.py (Python)

import sys
import test_cython
iterations = 0
if len(sys.argv) > 1:
    iterations = int(sys.argv[1])
test_cython.test_cython(iterations)

test_cython.pyx (Cython)

import sys
from libc.stdlib cimport malloc, free
def test_cython(iterations):
    cdef int element = 0
    cdef int iteration = 0
    cdef int innerloop = 0
    cdef double total = 0.0
    cdef int array_length = 100000000
    cdef double *array = <double *>malloc(array_length * sizeof(double))
    print 'iterations', iterations
    while element < array_length:
        array[element] = element
        element += 1
    while iteration < iterations:
        innerloop = 0
        while innerloop < 1000000000:
            total += array[(iteration + innerloop) % array_length];
            innerloop += 1
        iteration += 1
    print 'sum', total
    free(array)
    array = NULL

setup_cython.py (Python)

from distutils.core import setup
from Cython.Build import cythonize
setup(name = 'test cython', ext_modules = cythonize("test_cython.pyx"))

 

7、JavaScript

 

test.js (JavaScript)

#!/usr/bin/node --max-old-space-size=4096

var element = 0;
var iteration = 0;
var iterations = 0;
var innerloop = 0;
var sum = 0.0;
var array_length = 100000000;
var array = new Array(array_length);
var argc = process.argv.length
if (argc > 2)
    iterations = process.argv[2];
console.log("iterations " + iterations);
for (element = 0; element < array_length; element++)
    array[element] = element;
for (iteration = 0; iteration < iterations; iteration++)
    for (innerloop = 0; innerloop < 1000000000; innerloop++)
        sum += array[(iteration + innerloop) % array_length];
console.log("sum " + sum);
array = 0

正常情况下,javascript在Web浏览器中运行,但是node.js允许javascript在服务器或命令行上运行。

 

8、Perl

 

test.pl (Perl)


#!/usr/bin/perl

$element = 0.0;
$iteration = 0;
$iterations = 0;
$innerloop = 0;
$sum = 0.0;
$array_length = 100000000;
@array = [];
$argc = @ARGV;
if ($argc > 0) {
    $iterations = $ARGV[0];
}
print("iterations $iterations\n");
for ($element = 0.0; $element < 100000000.0; $element++) {
    $array[$element] = $element;
}
for ($iteration = 0; $iteration < $iterations; $iteration++) {
    for ($innerloop = 0; $innerloop < 1000000000; $innerloop++) {
        $sum += $array[($iteration + $innerloop) % $array_length];
    }
}
print("sum $sum\n");
@array = [];

 

9、Ruby

 

test.rb (Ruby)

#!/usr/bin/ruby
​
require 'matrix'
element = 0.0
iteration = 0
iterations = 0
innerloop = 0
sum = 0.0
array_length = 100000000
array = Array.new(array_length) {0.0}
vector = [array]
if ARGV[0]
    iterations = ARGV[0].to_i
end
puts "iterations #{iterations}"
for element in 0..array_length-1
    vector[element] = element
end
for iteration in 0..iterations-1
    for innerloop in 0..1000000000-1
        sum = sum + vector[(iteration + innerloop) % array_length];
    end
end
printf("sum %E\n", sum);
array = nil

 

10、Pascal

 

test.pas (Pascal)

program testpascal;
uses sysutils;
type
    vector = array of double;
var
    element : longint;
    iteration : longint;
    iterations : longint;
    innerloop : longint;
    sum : double;
    array_length : longint;
    my_array : vector;
begin
    element := 0;
    iteration := 0;
    iterations := 0;
    innerloop := 0;
    sum := 0.0;
    array_length := 100000000;
    setlength(my_array, array_length);
    if paramcount > 0 then
        iterations := strtoint(paramstr(1));
    writeln('iterations ', iterations);
    for element := 0 to array_length-1 do
        my_array[element] := element;
    for iteration := 0 to iterations-1 do
        for innerloop := 0 to 1000000000-1 do
            sum := sum + my_array[(iteration + innerloop) mod array_length];
    writeln('sum ', sum);
    my_array := nil;
end.

 

11、Lua

 

test.lua (Lua)

#!/usr/bin/lua
element = 0
iteration = 0
iterations = 0
innerloop = 0
sum = 0
array_length = 100000000
array = {}
if #arg > 0 then
    iterations = tonumber(arg[1])
end
print("iterations ", iterations)
for element=0, array_length-1 do
    array[element] = element
end
for iteration=0, iterations-1 do
    for innerloop=0, 1000000000-1 do
        sum = sum + array[((iteration + innerloop) % array_length)]
    end
end
print("sum ", sum)
array = nil

 

12、PHP

 

test.php (PHP)

#!/usr/bin/php
<?php
ini_set('memory_limit', '-1');
$element = 0;
$iteration = 0;
$iterations = 0;
$innerloop = 0;
$sum = 0.0;
$array_length = 100000000;
$array[] = 0;
if ( $argc > 1 ) {
    $iterations = $argv[1];
}
fwrite(STDOUT, "iterations ". $iterations . "\n");
for ($element = 1; $element < $array_length; $element++) {
    $array[] = $element;
}
for ($iteration = 0; $iteration < $iterations; $iteration++) {
    for ($innerloop = 0; $innerloop < 1000000000; $innerloop++) {
        $sum = $sum + $array[($iteration + $innerloop) % $array_length];
    }
}
fwrite(STDOUT, "sum ". $sum . "\n");
$array = 0;
?>

Makefile

all:\
test-c-gcc test-c-clang\
test-cpp-g++ test-cpp-clang++\
test-java test.class\
test-go\
test-ada\
test_python.pyc test_python_cython.so\
test_numpy.pyc test_numpy_cython.so\
test_cython.so\
test-pascal
​
test-c-gcc: test.c
    gcc -O3 -o test-c-gcc test.c
test-c-clang: test.c
    clang -O3 -o test-c-clang test.c
​
test-cpp-g++: test.cpp
    g++ -O3 -o test-cpp-g++ test.cpp
test-cpp-clang++: test.cpp
    clang++ -O3 -o test-cpp-clang++ test.cpp
​
test-java: test.java
    gcj -O3 --main=test -o test-java test.java
test.class: test.java
    javac test.java
​
test-go: test.go
    go build -o test-go test.go
​
test-ada: test.adb
    gnatmake -O3 -o test-ada test.adb
​
test_python.pyc: test_python.py test-python.py
    python -m py_compile test_python.py
    python -m py_compile test-python.py
test_python_cython.so: test_python_cython.pyx setup_python_cython.py test-python-cython.py
    python setup_python_cython.py build_ext --inplace
    python -m py_compile test-python-cython.py
​
test_numpy.pyc: test_numpy.py test-numpy.py
    python -m py_compile test_numpy.py
    python -m py_compile test-numpy.py
test_numpy_cython.so: test_numpy_cython.pyx setup_numpy_cython.py test-numpy-cython.py
    python setup_numpy_cython.py build_ext --inplace
    python -m py_compile test-numpy-cython.py
​
test_cython.so: test_cython.pyx setup_cython.py test-cython.py
    python setup_cython.py build_ext --inplace
    python -m py_compile test-cython.py
​
test-pascal: test.pas
    fpc -O3 -otest-pascal test.pas
​
clean:
    rm -f *.o *.so *.pyc
    rm -f test-c-gcc test-c-clang test-cpp-g++ test-cpp-clang++
    rm -f test-java test.class test-go test-ada test.ali
    rm -rf build test_python_cython.c test_numpy_cython.c test_cython.c
    rm -f test-pascal
​
run_test: all
    echo "-------------------------------------"
    time -p ./test-c-gcc 100
    time -p ./test-c-clang 100
    time -p ./test-cpp-g++ 100
    time -p ./test-cpp-clang++ 100
    time -p ./test-java 100
    time -p java test 100
    time -p ./test-ada 100
    time -p ./test-go 100
    echo "Multiply the test-python.pyc time by 100 for comparison."
    time -p python test-python.pyc 1
    echo "Multiply the test-python-cython.pyc time by 100 for comparison."
    time -p python test-python-cython.pyc 1
    echo "Multiply the test-numpy.pyc time by 100 for comparison."
    time -p python test-numpy.pyc 1
    echo "Multiply the test-numpy-cython.pyc time by 100 for comparison."
    time -p python test-numpy-cython.pyc 1
    time -p python test-cython.pyc 100
    time -p ./test.js 100
    echo "Multiply the test.pl time by 100 for comparison."
    time -p ./test.pl 1
    echo "Multiply the test.rb time by 100 for comparison."
    time -p ./test.rb 1
    time -p ./test-pascal 100
    echo "Multiply the test.lua time by 100 for comparison."
    time -p ./test.lua 1
    echo "Multiply the test.php time by 100 for comparison."
    time -p ./test.php 1

测试结果:

结果表显示了所有内容,但我还是要强调一些观察结果。C是我测试过的最高性能语言。它也可能是最底层、最有能力和最难写入安全代码的代码。我惊讶地发现,c/c++源码生成的clang/clang++比gcc/g++的执行速度要快。更高的可执行文件。排在第二的是C++,下面的排序依次是本地编译的Java/gcj,然后是Ad。本地编译的Java/gcj是使用自动垃圾收集的语言中,最快的语言。

Java/JavaC/JVM的执行时间是有误的,因为当所有其他东西都只在一个CPU核上耗尽时,它就耗尽了两个CPU。所以,尽管它比Cython完成得快一点,但它使用的CPU资源是Cython的两倍。在效率方面,它可能在Cython和Pascal或者Go之间。

脚本语言的性能明显低于本机可执行文件。动态类型、解释、垃圾收集和面向对象数组实现可能是许多问题的根源。非预编译脚本语言中最引人注目的是在node.js上运行的javascript。它不像JVM上运行的Java字节码那么快,但是它比我测试的脚本语言的速度要快得多。

最高性能的语言也生成最小的本地可执行文件。Pascal and Go的可执行文件看起来有点臃肿。许多脚本和字节码都非常小,但是python/cython的字节码本地组合最终介于高效的本地可执行文件和pascal之间。

内存消耗:内存高效的语言在0.8GB范围内。正如预期的那样,许多脚本语言的内存效率较低,因为它们所做的一切都是自动的幕后工作,而且在许多情况下数组的实现效率很低。最差的两个内存执行器是6GB的Perl和14GB的PHP。

我当然不是所有这些语言的专家。可能我忽略了一些语言特性,这些特性将使实现更加高效。