【问题标题】:Java vs .NET performance [closed]Java 与 .NET 的性能 [关闭]
【发布时间】:2015-07-08 03:54:30
【问题描述】:

在我编写了这段小代码来比较我的计算机中的 .NET 4.5 和 Java 8 性能后,我感到非常惊讶:

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();
    }
}

这里是 Java 版本:

    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));
    }

}

在我的计算机中,这段 C# 代码运行大约需要 5200 毫秒,而 Java 版本大约需要 2800 毫秒(!!!)。 我实际上预计 .NET 版本会比 Java 运行得更快(或至少接近),但对这个结果感到非常惊讶。

注意:我在 Visual Studio 之外运行以发布模式编译的 .NET 版本。

有人能解释一下这个结果吗?这真的正确吗? 我怎样才能重写这段代码,使 C#.NET 版本在执行速度上更接近 Java 版本?

[编辑]

好吧,我知道这不是一个真正有效的基准测试或公平的比较,但我如何重写这段代码以使 C#.NET 版本在执行速度上更接近 Java 版本? 尝试了任何形式(直接操作锯齿状数组,通过 getter 等),但测试运行得更慢。

[编辑 2]

编辑测试,使宽度和高度 = 500,循环 = 5000。 现在,.NET 版本大约需要 6300 毫秒,Java 版本大约需要 3700 毫秒。当然,每个版本都运行了多次测试。

[编辑 3]

刚刚使用平面数组而不是二维数组编写了一个类似的测试,这次 .NET 版本的运行速度与 Java 相同甚至更快。是这样吗? C#.NET 的交错数组只是比 Java 的多维数组慢?

【问题讨论】:

  • 我也很惊讶!问:你能发布 Java 版本吗?
  • 您需要进行适当的基准测试才能获得有意义的结果,但无论如何测试都不公平。在 java 版本中,您正在执行 array[i][j] *= a.getArray()[i][j]; 如果我正确理解复合赋值,它只会访问一次数组。在 C# 版本中,您使用的是索引器,因此您不是直接访问数组,而是通过 getset 方法。
  • 存在 很多 种可能存在这种差异的原因。当然,每个循环只运行 10 个循环,您主要是在测试 JIT 编译器,而不是代码本身。所以测试本身甚至是无效的。即使有效的测试显示出差异,仍然存在使用适当技术以每种语言写作的问题。苹果与苹果之间的比较很难做到正确,而这绝对不是。
  • 如果您没有选择 widthheight 相等,则此 jagged = new int[width][]; 可能会导致 IndexOutOfRangeException
  • AFAIK Java 编译器在展开循环时更具“侵略性”,这对短循环产生巨大影响。我已经看到一个例子,其中 Java 在 Eratosthenes 筛子的教科书实现中实际上优于本机代码(用 C++ 编写)。因此,您可能还想尝试更多的迭代。当然,这仍然不允许对 Java 与 C#/.NET 的性能进行一般性判断。

标签: java c# performance jvm clr


【解决方案1】:

您无法根据单个实例来判断性能。您需要为多个实例执行此操作。如果您想获得有关性能的具体答案,我建议您阅读quorablogSO

【讨论】:

    【解决方案2】:

    每当您进行任何类型的基准测试或性能分析时,您都需要提出很多问题,并使用(解释为 Tanenbaum)“一公吨盐”得出任何特定结果。

    但是....

    我复制粘贴了你的代码,这就是我得到的:

    Compiler      Version   Timing
    --------      -------   ------
    MSVS 2012     C# 5      4448.0
    Eclipse Luna  JRE 1.7    977.0
    

    因此,Java 程序的运行速度比 C# 程序快 4.5 倍。

    我还运行了 MSVS“分析向导”:

    https://msdn.microsoft.com/en-us/library/dd264959.aspx

    Large picture

    您可能从屏幕截图中看到,此配置文件中的“大猪”是 ArrayTest.get_item(int32, int32),它消耗了 近一半 的执行时间:

    Large picture

    【讨论】:

    • 哇!你能用直接数组访问重写这个测试并在分析器中测试它并告诉我会发生什么吗?就我而言,测试运行得更慢,而且我没有 VS Pro os 任何分析器来查看发生了什么。
    • 我们试图将 Java 中的直接访问与 C# 中的指针访问进行比较。简而言之,为了存储/加载数组的下一个值,java 使用普通的mov 和指针碰撞inc,c# 使用更昂贵的操作lea,它计算每次加载/存储时值的有效地址!我已将测试更改为直接访问,并为 java 和 C# 得到相同的结果
    • 好吧,代码变快了一点,但这还不够。我必须对循环二维数组的方式进行一些更改,以便获得与 Java 相同的结果。
    猜你喜欢
    • 2013-12-01
    • 2011-08-04
    • 1970-01-01
    • 2013-01-05
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    相关资源
    最近更新 更多