【发布时间】: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# 版本中,您使用的是索引器,因此您不是直接访问数组,而是通过get和set方法。 -
存在 很多 种可能存在这种差异的原因。当然,每个循环只运行 10 个循环,您主要是在测试 JIT 编译器,而不是代码本身。所以测试本身甚至是无效的。即使有效的测试显示出差异,仍然存在使用适当技术以每种语言写作的问题。苹果与苹果之间的比较很难做到正确,而这绝对不是。
-
如果您没有选择
width和height相等,则此jagged = new int[width][];可能会导致IndexOutOfRangeException -
AFAIK Java 编译器在展开循环时更具“侵略性”,这对短循环产生巨大影响。我已经看到一个例子,其中 Java 在 Eratosthenes 筛子的教科书实现中实际上优于本机代码(用 C++ 编写)。因此,您可能还想尝试更多的迭代。当然,这仍然不允许对 Java 与 C#/.NET 的性能进行一般性判断。
标签: java c# performance jvm clr