C#.NET和Java中的2d阵列性能

C#.NET和Java中的2d阵列性能,java,c#,.net,arrays,performance,Java,C#,.net,Arrays,Performance,我编写了一些代码来测试C#(.NETCLR)和Java(Java8,Windows)中数组的性能。对于普通平面阵列,.NET显示出比Java快一点 当我编写一些测试2d数组(使用锯齿数组)的代码时,我注意到Java和C#之间存在明显的差距。Java版本运行速度比C快2倍以上 这是我的C代码: 类数组测试 { 公共int[][]锯齿形; 公共阵列测试(整数宽度、整数高度) { 高度=高度; 宽度=宽度; 随机rng=新随机(); 锯齿状=新整数[高度][]; 对于(int i=0;i

我编写了一些代码来测试C#(.NETCLR)和Java(Java8,Windows)中数组的性能。对于普通平面阵列,.NET显示出比Java快一点

当我编写一些测试2d数组(使用锯齿数组)的代码时,我注意到Java和C#之间存在明显的差距。Java版本运行速度比C快2倍以上

这是我的C代码:

类数组测试
{
公共int[][]锯齿形;
公共阵列测试(整数宽度、整数高度)
{
高度=高度;
宽度=宽度;
随机rng=新随机();
锯齿状=新整数[高度][];
对于(int i=0;i
在我的电脑中,被测部分大约需要2200ms才能运行

以下是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(1024);
            }
        }
    }

    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.array[i][j];
            }
        }
    }

}

    public class Main {

        public static void main(String[] args) {
            // TODO Auto-generated method stub
            final int loop = 500;
            int width = 800,
                    height = 800;
            ArrayTest a1 = new ArrayTest(width, height),
                    a2 = new ArrayTest(width, height);
            long start, end;


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

    }
公共类数组测试{
私人int宽度、高度;
私有int[][]数组;
公共阵列测试(整数宽度、整数高度){
这个。宽度=宽度;
高度=高度;
数组=新整数[高度][宽度];
随机rng=新随机();
对于(int i=0;i
运行大约需要930毫秒

到目前为止,它是C#2200ms与java930ms的对比

但是,当我将C#方法更改为如下所示时:

public void DoMath(ArrayTest a)
    {
        int[][] _jagged = this.jagged,
            _a = a.jagged;
        int[] __jagged, __a;
        for (int i = 0; i < _jagged.Length; i++)
        {
            __jagged = _jagged[i];
            __a = _a[i];
            for (int j = 0; j < __jagged.Length; j++)
            {
                __jagged[j] *= __a[j];
            }
        }
    }
公共无效域(ArrayTest a)
{
int[][]\u jagged=this.jagged,
_a=a.锯齿状;
int[]\uuuuuuuuuuuuuuuuua型;
对于(int i=0;i<_jagged.Length;i++)
{
__锯齿状的;
__a=_a[i];
对于(int j=0;j<\uu jagged.Length;j++)
{
__锯齿状[j]*=u a[j];
}
}
}
然后我的C#代码变得和Java一样快!(930毫秒) 我花了很长时间才找到这段代码,我仍然不知道为什么它比第一个版本更快(而且更难看)

因此,以下是我的问题:

  • 为什么最后一个代码比第一个代码更有效
  • 我可以重写它,使它变得更有效(或不那么难看,但像这个一样有效)
  • [编辑]

    我使用的是.NET4.5和Java8,它们都是控制台应用程序。 我运行的.NET版本处于发布模式,并且没有附加VS调试器

    [编辑2]


    需要明确的是:它不是一个微观基准或类似的东西。我只想通过2d数组使操作比Java更快(或与Java一样快),我更喜欢使用更干净的代码。

    尝试进行以下非常小的更改:

    public void DoMath(ArrayTest a)
    {
        int height = Height;
        int width = Width;
    
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    jagged[i][j] *= a.jagged[i][j];
                }
            }
    
    
    }
    
    公共无效域(ArrayTest a)
    {
    int高度=高度;
    整数宽度=宽度;
    对于(int i=0;i
    这几乎使我的机器的性能提高了三倍。您是否将C#项目设置为在发布模式或调试模式下运行?这有很大的区别

    以下是我的结果:

    • 如您所知:5555ms(在我的笔记本电脑上运行,调试模式,已连接调试器)
    • 经过上述修改(与上述条件相同):1808ms
    • 在调试器(CTRL-F5)外部以发布模式运行: 907毫秒
    那么,为什么这个小小的变化会产生如此大的影响呢?在调试模式下运行会禁用C#中的优化,因此编译器不会优化对
    Height
    Width
    属性的调用。每次循环时,它都会转到属性,然后属性必须转到backing字段以获取值,然后返回

    因为您在Java中使用的是字段而不是属性,所以您不必
    public void DoMath(ArrayTest a)
    {
        int height = Height;
        int width = Width;
    
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    jagged[i][j] *= a.jagged[i][j];
                }
            }
    
    
    }
    
    public void DoMath(ArrayTest a)
    {
        //Stopwatch st = new Stopwatch();
        //st.Start();
        //for (int i = 0; i < Height; i++)
        Parallel.For(0, Height, (i) =>
        {
            for (int j = 0; j < Width; j++)
            {
                jagged[i][j] *= a.jagged[i][j];
            }
        });
        //st.Stop();
        //Console.WriteLine(st.ElapsedMilliseconds);
    }
    
    public void DoMath(ArrayTest a)
    {
        Parallel.For(0, Height, (i) =>
        {
            int[] _jagged = jagged[i];
            int[] _a = a.jagged[i];
            for (int j = 0; j < _jagged.Length; j++)
            {
                _jagged[j] *= _a[j];
            }
        });
        //st.Stop();
    }
    
    class ArrayTest
        {
            public int [][] jagged;
    
            public ArrayTest(int width, int height)
            {
                Height = height;
                Width = width;
                Random rng = new Random();
                jagged = new int[height][];
                for (int i = 0; i < height; i++)
                {
                    jagged[i] = new int[width];
                    for (int j = 0; j < width; j++)
                    {
                        jagged[i][j] = rng.Next(1024);
                    }
                }
            }
    
            public int Height { get; private set; }
    
            public int Width { get; private set; }
    
            public int this[int i, int j]
            {
                get
                {
                    return jagged[i][j];
                }
                set
                {
                    jagged[i][j] = value;
                }
            }
    
            public void DoMath(ArrayTest a)
            {
                int width = Width, height = Height;
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        //jagged[i][j] *= a.jagged[i][j];
                        jagged[i][j] = jagged[i][j] * a.jagged[i][j];
                    }
                }
            }
    
            public void DoMathProp(ArrayTest a)
            {
                int width = Width, height = Height;
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        //this[i, j] *= a[i, j];
                        this[i, j] = this[i, j] * a[i, j];
                    }
                }
            }
    
            public void DoMathFaster(ArrayTest a)
            {
                int width = Width, height = Height;
                int[][] jagged = this.jagged,
                    _a = a.jagged;
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        //jagged[i][j] *= _a[i][j];
                        jagged[i][j] = jagged[i][j] * _a[i][j];
                    }
                }
            }
    
            public void DoMathForeach(ArrayTest a)
            {
                int i = 0, j = 0;
                foreach (var line in a.jagged)
                {
                    j = 0;
                    foreach (var item in line)
                    {
                        //jagged[i][j] *= item;
                        jagged[i][j] = jagged[i][j] * item;
                        j++;
                    }
                    i++;
                }
            }
    
            public void DoMathFastest(ArrayTest a)
            {
                int[][] _jagged = this.jagged,
                    _a = a.jagged;
                int[] __jagged, __a;
                for (int i = 0; i < _jagged.Length; i++)
                {
                    __jagged = _jagged[i];
                    __a = _a[i];
                    for (int j = 0; j < __jagged.Length; j++)
                    {
                        //__jagged[j] *= __a[j];
                        __jagged[j] = __jagged[j] * __a[j];
                    }
                }
            }
    
            public int Sum()
            {
                int sum = 15;
                int[][] jagged = this.jagged;
                for (int i = 0; i < jagged.Length; i++)
                {
                    for (int j = 0; j < jagged[i].Length; j++)
                    {
                        sum = sum + jagged[i][j];
                    }
                }
                return sum;
            }
    
            public int SumProp()
            {
                int sum = 15;
                int width = Width, height = Height;
                for (int i = 0; i < height; i++)
                {
                    for (int j = 0; j < width; j++)
                    {
                        sum = sum + this[i, j];
                    }
                }
                return sum;
            }
    
            public int SumForeach()
            {
                int sum = 15;
                foreach (var line in jagged)
                {
                    foreach (var item in line)
                    {
                        sum += item;
                    }
                }
                return sum;
            }
    
            public int SumFast()
            {
                int sum = 15;
                int[][] jagged = this.jagged;
                for (int i = 0; i < jagged.Length; i++)
                {
                    int[] _jagged = jagged[i];
                    for (int j = 0; j < jagged[i].Length; j++)
                    {
                        sum += _jagged[j];
                    }
                }
                return sum;
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                const int loop = 1000;
                int width = 800, height = 800;
                ArrayTest a1 = new ArrayTest(width, height),
                    a2 = new ArrayTest(width, height);
    
                Stopwatch sw = new Stopwatch();
    
                //DoMath
                sw.Start();
                for (int i = 0; i < loop; i++)
                {
                    a1.DoMath(a2);
                }
                sw.Stop();
    
                Console.WriteLine("DoMath: " + sw.ElapsedMilliseconds);
    
                //DoMathProp
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.DoMathProp(a2);
                }
                sw.Stop();
    
                Console.WriteLine("DoMathProp: " + sw.ElapsedMilliseconds);
    
                //DoMathFaster
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.DoMathFaster(a2);
                }
                sw.Stop();
    
                Console.WriteLine("DoMathFaster: " + sw.ElapsedMilliseconds);
    
                //DoMathForeach
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.DoMathForeach(a2);
                }
                sw.Stop();
    
                Console.WriteLine("DoMathForeach: " + sw.ElapsedMilliseconds);
    
                //DoMathFastest
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.DoMathFastest(a2);
                }
                sw.Stop();
    
                Console.WriteLine("DoMathFastest: " + sw.ElapsedMilliseconds);
    
                //Sum
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.Sum();
                }
                sw.Stop();
    
                Console.WriteLine("Sum: " + sw.ElapsedMilliseconds);
    
                //SumProp
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.SumProp();
                }
                sw.Stop();
    
                Console.WriteLine("SumProp: " + sw.ElapsedMilliseconds);
    
                //SumForeach
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.SumForeach();
                }
                sw.Stop();
    
                Console.WriteLine("SumForeach: " + sw.ElapsedMilliseconds);
    
                //SumFast
                sw.Restart();
                for (int i = 0; i < loop; i++)
                {
                    a1.SumFast();
                }
                sw.Stop();
    
                Console.WriteLine("SumFast: " + sw.ElapsedMilliseconds);
    
                Console.ReadKey();
            }
        }
    
    Run #1:
    DoMath: 3931
    DoMathProp: 3011
    DoMathFaster: 3358
    DoMathForeach: 3102
    DoMathFastest: 1770
    Sum: 729
    SumProp: 745
    SumForeach: 709
    SumFast: 753
    
    Run #2:
    DoMath: 3945
    DoMathProp: 2978
    DoMathFaster: 3311
    DoMathForeach: 3102
    DoMathFastest: 1764
    Sum: 730
    SumProp: 744
    SumForeach: 708
    SumFast: 753
    
    Run #3:
    DoMath: 4041
    DoMathProp: 2976
    DoMathFaster: 3314
    DoMathForeach: 3092
    DoMathFastest: 1777
    Sum: 732
    SumProp: 748
    SumForeach: 714
    SumFast: 751
    
    Run #1:
    DoMath: 3045
    DoMathProp: 2977
    DoMathFaster: 2681
    DoMathForeach: 3394
    DoMathFastest: 1802
    Sum: 738
    SumProp: 753
    SumForeach: 716
    SumFast: 755
    
    Run #2:
    DoMath: 2966
    DoMathProp: 2953
    DoMathFaster: 2631
    DoMathForeach: 3382
    DoMathFastest: 1747
    Sum: 734
    SumProp: 738
    SumForeach: 703
    SumFast: 755
    
    Run #3:
    DoMath: 2965
    DoMathProp: 2959
    DoMathFaster: 2642
    DoMathForeach: 3383
    DoMathFastest: 1773
    Sum: 729
    SumProp: 747
    SumForeach: 707
    SumFast: 750
    
    Run #1:
    doMath: 1728.550504
    doMathProp: 1747.916189
    doMathFaster: 1736.039763
    doMathForeach: 1734.981001
    doMathFastest: 1732.675896
    sum: 626.478196
    sumProp: 627.959249
    sumForeach: 629.493964
    sumFast: 649.372465
    
    Run #2:
    doMath: 1791.048725
    doMathProp: 1888.965311
    doMathFaster: 1826.43116
    doMathForeach: 1806.1341
    doMathFastest: 1833.68291
    sum: 772.088533
    sumProp: 697.429715
    sumForeach: 660.004415
    sumFast: 756.06105
    
    Run #3:
    doMath: 1819.834545
    doMathProp: 1821.309067
    doMathFaster: 1809.052345
    doMathForeach: 1719.76124
    doMathFastest: 1719.466335
    sum: 616.398258
    sumProp: 627.816464
    sumForeach: 650.758328
    sumFast: 642.416087
    
    __jagged = _jagged[i];
     __a = _a[i];
    
        public void DoMath(ArrayTest a)
        {
            int[][] arr = a.jagged;
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    jagged[i][j] *= arr[i][j];
                }
            }
        }