Java vs .NETTO-performance

Ich habe mich selbst sehr überrascht, nachdem ich schrieb dieses kleine code zu vergleichen .NET 4.5 und Java 8 Leistung in meinem Rechner:

class ArrayTest
{
    public int[][] jagged;

    public ArrayTest(int width, int height)
    {
        Height = height;
        Width = width;
        Random rng = new Random();
        jagged = new int[width][];
        for (int i = 0; i < height; i++)
        {
            jagged[i] = new int[width];
            for (int j = 0; j < jagged[i][j]; j++)
            {
                jagged[i][j] = rng.Next(2048);
            }
        }
    }
    public int this[int i, int j]
    {
        get
        {
            return jagged[i][j];
        }
        set
        {
            jagged[i][j] = value;
        }
    }

    public void DoMath(ArrayTest a)
    {
        for (int i = 0; i < Height; i++)
        {
            for (int j = 0; j < Width; j++)
            {
                this[i, j] *= a[i, j];
            }
        }
    }

    public int Height { get; private set; }

    public int Width { get; private set; }
}



class Program
{
    static void Main(string[] args)
    {
        Random rng = new Random();
        const int loop = 10;
        int width = 10000,
            height = 10000;

        ArrayTest a1 = new ArrayTest(width, height),
            a2 = new ArrayTest(width, height);


        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < loop; i++)
        {
            a1.DoMath(a2);
        }
        sw.Stop();

        Console.WriteLine("Time taken: " + sw.ElapsedMilliseconds);

        Console.ReadKey();
    }
}

Hier ist die Java-version:

    public class ArrayTest {
    private int width, height;
    private int[][] array;

    public ArrayTest(int width, int height) {
        this.width = width;
        this.height = height;
        array = new int[height][width];
        Random rng = new Random();
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                array[i][j] = rng.nextInt(2048);
            }
        }
    }

    public int getWidth() {
        return width;
    }
    public void setWidth(int width) {
        this.width = width;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public int[][] getArray() {
        return array;
    }

    public void doMath(ArrayTest a) {
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                array[i][j] *= a.getArray()[i][j];
            }
        }
    }

}

public class Main {

    public static void main(String[] args) {
        //TODO Auto-generated method stub
        final int loops = 10;
        int width = 10000, height = 10000;
        ArrayTest a1 = new ArrayTest(width, height),
                a2 = new ArrayTest(width, height);

        long start, end;


        start = java.lang.System.currentTimeMillis();
        for (int i = 0; i < loops; i++) {
            a1.doMath(a2);
        }
        end = java.lang.System.currentTimeMillis();
        System.out.println("Elapsed time: " + (float)(end - start));
    }

}

In meinem computer, auf dem diese C# - code ist die Einnahme über 5200ms zu laufen, und die Java version ist die Einnahme über 2800ms(!!!).
Ich hatte eigentlich erwartet, dass die .NET-version würde schneller laufen (oder zumindest in der Nähe) als Java, aber wurde sehr überrascht, mit diesem Ergebnis.

Hinweis: ich lief die .NET-version im release-Modus, die außerhalb von Visual Studio.

Kann jemand erklären Sie dieses Ergebnis? Ist das wirklich richtig?
Wie könnte ich diese umschreiben von code, so dass die C#.NET version näher an der Java one in der Ausführungsgeschwindigkeit?

[Bearbeiten]

Gut, ich weiß, das ist nicht wirklich gültig, benchmarking oder ein fairer Vergleich, aber wie könnte ich diese umschreiben von code, so dass die C#.NET version näher an der Java one in der Ausführungsgeschwindigkeit?
Versucht in allen Formen (Manipulation der jagged-array direkt über eine get-Methode, etc), aber der test lief auch langsamer.

[edit 2]

Bearbeitet den test, so dass ich die Breite und height = 500, und loop = 5000.
Jetzt bekomme ich über 6300ms für .NET-version, und über 3700ms für Java-version. lief der test mehrere Male für jede version, natürlich.

[edit 3]

Schrieb gerade einen ähnlichen test mit Flachbild-arrays statt mit 2D-arrays, und dieses mal die .NET-version läuft genauso oder sogar schneller als Java. So ist es das?
C#.NET's jagged arrays sind nur langsamer als Java mehrdimensionale arrays?

  • Ich bin überrascht, auch! Q: Könnten Sie post von der Java-version?
  • Könnte man auch angeben, wie viele Läufe Sie für jede version und was die Durchschnittliche Leistung war? Es könnte sein, dass sich der Zeitaufwand ist viel größer, für den ersten run und dann drastisch abnimmt.
  • 2x Unterschied zwischen OOP-Sprachen klingt das komisch. Können Sie Sie ausführen, die in einem profiler, um zu sehen, wo die hot spots sind? Könnte nur ein Unterschied in der PRNGs; das ist eine gute Menge von Zufallszahlen ausspucken. (200 Millionen, wenn ich lese dieses Recht?) Oder könnte die Nutzung von operatorüberladungen in .NET. Oder irgendetwas, denke ich.
  • Sie tun müssen, um die richtige benchmarking um sinnvolle Ergebnisse, aber der test ist nicht fair sowieso. In der java-version du tust array[i][j] *= a.getArray()[i][j]; die greift nur auf das array einmal wenn ich verstehen zusammengesetzte Zuweisung korrekt. In der C# - version, die Sie verwenden Indexer, so dass Sie nicht Zugriff auf das array direkt, sondern über die get und set Methoden.
  • Es gibt viele Gründe, solch ein Unterschied existieren könnte. Für Sie sicher, laufen nur 10 Windungen auf, Sie sind meistens die Prüfung der JIT-compiler nicht den code selbst. Also der test selbst ist auch nicht gültig. Selbst wenn eine gültige-test zeigte einen Unterschied, es ist noch die Frage zu schreiben, in jeder Sprache mit Hilfe der entsprechenden Techniken. Äpfel-zu-äpfel-Vergleiche sind sehr schwer zu bekommen Recht, und dieses ist definitiv nicht.
  • es gibt wichtige Unterschiede, aber ich denke, dass der indexer vs getArray() ist die nicht-offensichtliche Bedeutung. Das ist, sowohl zu einem einzigen Aufruf der Methode, und ein 2d-array-lookup. Der Grund, es ist wichtig (IMHO) ist, dass in der Java-Szenario, der JIT-compiler die Chance hat zu erkennen, die invariantly constrained index und damit umgehen kann, bounds-checking auf die Suche. Der C# - code möglicherweise oder möglicherweise nicht haben, die Möglichkeit, sich je nach a) ob der indexer inlined, und b) ob das passiert vor oder nach dem bounds-checking-Optimierung (wenn überhaupt) durchgeführt wird.
  • Diese jagged = new int[width][]; verursacht haben könnte eine IndexOutOfRangeException wenn Sie nicht gewählt width und height gleich zu sein
  • AFAIK der Java-compiler ist mehr "aggressiv" mit unrolling Schleifen, die einen riesigen Unterschied machen kann für kurze Schleifen. Ich habe ein Beispiel gesehen, in dem Java wirklich besser als native-code (geschrieben in C++) in einem lehrbuch die Umsetzung des Sieb des Eratosthenes. So möchten Sie vielleicht zu versuchen, mehr Iterationen als gut. Noch wird nicht zulassen, dass ein Allgemeines Urteil über die Leistung von Java vs. C#/.NETTO natürlich.
  • Vielen Dank Alex, nicht, dass se.
  • Tja, der test, ich habe versucht zu umschreiben, dass es mit direktem Zugriff auf das array statt der Eigenschaft(this[i, j]), und auch der Rückkehr das array über get-und dann darauf zugreift, wie die Java-version, aber in beiden Fällen der test lief sogar langsamer.
  • Bitte verwenden Sie DoMath(int[][] jagged) statt doMath(ArrayTest a). In Ihrem Fall, die Sie testen, direct access in Java-mit-pointer-Zugriff in C#. Ich kann Ihnen weitere detaillierte Informationen, aber deine Frage ist auf Eis. In wenigen Worten, um zu speichern/laden der nächste Wert des Arrays benutzt java plain mov mit Zeiger bump inc, c# verwendet, teurer Betrieb lea die compute effektive Adresse der Wert auf jeder laden/speichern! Ich habe geändert den test, um direkten Zugang und bekam die gleichen Ergebnisse für java-und C#
  • Macht Sinn. Aber ich änderte meine Methode, um das Formular, das Sie sugested, und ich noch zu erhalten das gleiche Ergebnis: Für ein flaches array, C#.NET läuft deutlich schneller, und für ein verzweigtes 2d-array, Java läuft viel schneller. Dies könnte sein, nur in meinem computer?
  • Der offensichtlichste Unterschied ist, dass die .NET-version ist der Zugriff auf das array und die Höhe/Breite Felder mithilfe von property-Accessoren (also Methodenaufrufe) in der Erwägung, dass die Java-version ist die Verwendung von Feldern (d.h. direkt Zugriff auf Globale Variablen). Ich könnte mir vorstellen, dies würde einen großen Unterschied machen, um die Leistung.

InformationsquelleAutor Yan Paulo | 2015-04-29
Schreibe einen Kommentar