Prueba de rendimiento de un método de eliminación de matrices en Kotlin, Java, C # y Nim

Porque

Uno de mis proyectos está escrito en Kotlin. Es una aplicación de base de datos multidimensional, por lo que operará la matriz int con mucha frecuencia. Si hay un segmento del programa, necesita realizar cientos de millones de acciones de limpieza de matriz, similar a este código:

Arrays.fill (objetivo, 0);

Este Arrays.fill es en realidad una implementación de jdk, muy simple, es un bucle for para llenar los datos.

Así que quiero mejorarlo, escribir la longitud de la matriz común en una sola implementación, por ejemplo, el método para borrar 8 longitudes es el siguiente:

fun clear8 (target: IntArray) {
     if (target.size <8 ) {
         throw IndexOutOfBoundsException () 
    } 
    target [ 0] = 0 
    target [ 1] = 0 
    target [ 2] = 0 
    target [ 3] = 0 
    target [ 4] = 0 
    objetivo [ 5] = 0 
    objetivo [ 6] = 0 
    objetivo [ 7] = 0 
}

No dudes de tus ojos, tal escritura suele ser efectiva. Un buen compilador optimizará el código que escribí. Por supuesto, un mejor compilador optimizará el bucle for de una matriz simple.

Entonces probémoslo.

import java.util. *
 import kotlin.system.measureNanoTime 

fun main () { 
    test3 () 
} 


private fun test3 () { 
    val size = 8 
    val time2 = measureNanoTime { 
        val target = IntArray (size)
         for (i en 0 hasta 10_0000_0000 ) { 
            IntArrays.clear8 (target) 
        } 
    } 
    println ( "fill $ size $ time2" ) 

    val time1 = measureNanoTime { 
        val target = IntArray (size)
         para (i en 0hasta 10_0000_0000) { 
            Arrays.fill (target, 0 ) 
        } 
    } 
    println ( "Arrays.fill $ size $ time1" ) 
    println () 
} 

objeto interno IntArrays { 
    fun clear8 (target: IntArray) { 
        if (target.size <8 ) {
             throw IndexOutOfBoundsException () 
        } 
        objetivo [ 0] = 0 
        objetivo [ 1] = 0 
        objetivo [ 2] = 0 
        objetivo [ 3] = 0 
        objetivo [ 4] = 0 
        objetivo [ 5] = 0 
        objetivo [ 6] = 0
        objetivo [ 7] = 0 
    } 
}

Resultados de la prueba:

fill8 55,408,200
Arrays.fill8 2,262,171,100

¡Se puede ver que, usando el método de despliegue, el rendimiento es 40 veces mayor que los 2.2 segundos que viene con Java! !

Comparación de rendimiento con Java

Lamento que el compilador de Kotlin sea realmente fuerte, pero piénselo detenidamente, no está bien, Kotlin está basado en la JVM, y el crédito debería ser que el tiempo de ejecución de la máquina virtual de Java es muy poderoso, por lo que si este programa se convierte a Java, es mejor escribir directamente Rendimiento rápido, al menos consistente. Solo hazlo.

// IntArrays.java 
import java.util.Arrays; 

Clase final  IntArrays {
     static void clear8 ( int [] target) {
 / *         if (target.length <8) { 
            throw new IndexOutOfBoundsException (); 
        } * / 
        target [ 0] = 0 ; 
        objetivo [ 1] = 0 ; 
        objetivo [ 2] = 0 ; 
        objetivo [ 3] = 0 ; 
        objetivo [ 4] = 0 ; 
        objetivo [ 5] = 0 ; 
        objetivo [ 6] = 0 ; 
        objetivo [ 7] = 0 ; 
    } 
} 

// IntArraysDemoJava.java 
import java.util.Arrays; 

public  final  class IntArraysDemoJava {
     public  static  void main (String [] var0) { 
        test1 (); 
    } 

    Privada  estática  vacío test1 () {
         larga count = 1000000000 ;
        inicio largo = System.nanoTime ();
        final  int [] target = nuevo  int [8 ]; 

        para ( inti = 0; yo <cuento; i ++ ) { 
            IntArrays.clear8 (objetivo); 
        } 
        tiempo largo2 = System.nanoTime () - inicio; 
        System.out.println ( "fill8" + tiempo2); 

        inicio = System.nanoTime ();
        for ( int i = 0; i <count; i ++ ) { 
            Arrays.fill (target, 0 ); 
        } 

        long time1 = System.nanoTime () - inicio; 
        System.out.println ( "Arrays.fill8" + tiempo1); 
        System.out.println (); 
    } 
}
Implementación de Java

Los resultados de la prueba son los siguientes:

fill8 2,018,500,800
Arrays.fill8 2,234,306,500

Dios mío, este tipo de optimización casi no tiene efecto en Java. No encontré ningún concepto de parámetros de compilación de lanzamiento. A lo sumo, solo tiene debug = false. Lo incluí en gradle.

compileJava { 
    options.debug = false 
}

Entonces, ¿eso significa que el código de bytes generado por Kotlin es mejor que el código de bytes generado por Java?

Java Kotlin 
ALOAD 0 ALOAD 1 
ICONST_0 ICONST_0 
ICONST_0 ICONST_0 
IASTORE ASTORE 
  
ALOAD 0 ALOAD 1 
ICONST_1 ICONST_1 
ICONST_0 ICONST_0 
IASTORE IASTORE

El código de bytes es ligeramente diferente, si me preguntas por qué. Mi gallina . . . . .

Comparación con C #

Como fanático incondicional de .net, esta vez pensaré si c # es más rápido, sin mencionar que .net core 3 ha optimizado mucho el rendimiento,

Programa de clase {
    static  void Main ( string [] args) { 
       Test3.test1 (); 
   } 
} 

class Test3 
{ 
    public  static  void test1 () 
    {
         cuenta larga = 1000000000 ;
        var watch = System.Diagnostics.Stopwatch.StartNew ();
        int [] target = nuevo  int [ 8 ]; 

        para ( int i = 0 ; i <cuenta; i ++ ) 
        {  
            Clear8 (target);
        }
        watch.Stop (); 
        Console.WriteLine ( " fill8           " + watch.Elapsed); 

        watch.Restart (); 
        for ( int i = 0 ; i <count; i ++ ) 
        { 
            Array.Clear (target, 0 , 8 ); 
        } 

        watch.Stop (); 
        Console.WriteLine ( " Array.Clear8    " + watch.Elapsed); 
        Console.WriteLine (); 
    } 

    estático  vacío Clear8 ( int [] objetivo) 
    { 
        / *if (target.Length <8) 
        { 
            lanzar nuevo IndexOutOfRangeException (); 
        } * / 
        target [ 0 ] = 0 ; 
        objetivo [ 1 ] = 0 ; 
        objetivo [ 2 ] = 0 ; 
        objetivo [ 3 ] = 0 ; 
        objetivo [ 4 ] = 0 ; 
        objetivo [ 5 ] = 0 ; 
        objetivo [ 6 ] = 0 ; 
        objetivo [ 7 ] = 0; 
    } 
}

Resultados de la prueba:

fill8 00: 00: 02.7462676
Array.Clear8 00: 00: 08.4920514

En comparación con Java, es aún más lento, e incluso el Array.clear que viene con el sistema es aún más lento. ¿Cómo puedo soportarlo? Entonces, Span.Fill (0), que es un pase, es aún menos satisfactorio.

Rendimiento comparado con Nim

Se menciona el interés, luego use el lenguaje C para lograr uno ... No está escrito, soy estúpido ..., luego use Rust para implementar uno, o no se da cuenta, siga el tutorial paso a paso, Todavía no hecho ...

Finalmente lanzando un entorno Nim, um, sigue siendo simple.

tiempos de 
importación , strutils 
proc clear8 * [int] (target: var seq [int]) = 
    target [0] = 0 
    target [ 1] = 0 
    target [ 2] = 0 
    target [ 3] = 0 
    target [ 4] = 0 
    target [ 5] = 0 
    target [ 6] = 0 
    target [ 7] = 0 

proc clear * [int] (target: var seq [int]) =
     para i en 0 .. < target.len: 
        target [i] = 0 


proc test3 () =
    const size = 8 
    var start = epochTime () 
    var target = newseq [int] (size)
     para i en 0 .. < 10_0000_0000: 
        target.clear8 () 
    
    let elapsedStr = (epochTime () - start) .formatFloat (format = ffDecimal , precisión = 3 ) 
    echo " fill8          " , elapsedStr 

    start = epochTime ()
     para i en 0 .. < 10_0000_0000: 
        target.clear () 
    
    let elapsedStr2= (epochTime () - start) .formatFloat (format = ffDecimal, precision = 3 ) 
    echo " Arrays.fill    " , elapsedStr2 

test3 ()
lo

Para los resultados de la prueba, preste atención a agregar el parámetro --release.

fill8 3.499
Arrays.fill 5.825

Decepción y su decepción.

Observaciones

Todas las pruebas se realizaron en mi computadora de escritorio y la configuración es la siguiente:

AMD Ryzen 5 3600 6 Core 3.59 Ghz

8 GB de RAM

Windows 10 64 Professional Edition

Todas las pruebas se compilan con el lanzamiento.

Supongo que te gusta

Origin www.cnblogs.com/tansm/p/12684664.html
Recomendado
Clasificación