我正在测试crating +调用+使用虚方法放弃大量短生命对象的性能。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BoxingTest
{
public abstract class BoxedVal
{
public abstract BoxedVal Add(BoxedVal other);
public abstract bool LessThan(BoxedVal other);
public abstract bool GreaterThan(BoxedVal other);
}
public class BoxedInt : BoxedVal
{
public int Value;
public BoxedInt(int value)
{
Value = value;
}
public override BoxedVal Add(BoxedVal other)
{
BoxedInt i = other as BoxedInt;
return new BoxedInt(Value + i.Value);
}
public override bool LessThan(BoxedVal other)
{
BoxedInt i = other as BoxedInt;
return Value < i.Value;
}
public override bool GreaterThan(BoxedVal other)
{
BoxedInt i = other as BoxedInt;
return Value > i.Value;
}
}
class Program
{
private static int Fib(int nn)
{
BoxedVal one = new BoxedInt(1);
BoxedVal a = one;
BoxedVal b = one;
BoxedVal n = new BoxedInt(nn);
BoxedVal thousand = new BoxedInt(1000);
for (BoxedVal i = new BoxedInt(2); i.LessThan(n); i = i.Add(one))
{
BoxedVal c = a.Add(b);
a = b;
b = c;
if (b.GreaterThan(thousand))
{
a = one;
b = one;
}
}
return (b as BoxedInt).Value;
}
static void Main(string[] args)
{
int times = 5;
int n = 20000000;
int total = 0;
for (int i = 0; i < times; i++)
{
var start = DateTime.Now;
int val = Fib(n);
int dt = (DateTime.Now - start).Milliseconds;
total += dt;
Console.WriteLine(val);
Console.WriteLine("Elapsed: {0} ms", dt);
}
Console.WriteLine("Average: {0} ms", total / times);
Console.ReadLine();
}
}
}
package boxingtest;
abstract class BoxedVal
{
public abstract BoxedVal Add(BoxedVal other);
public abstract boolean LessThan(BoxedVal other);
public abstract boolean GreaterThan(BoxedVal other);
}
class BoxedInt extends BoxedVal
{
public int Value;
public BoxedInt(int value)
{
Value = value;
}
@Override
public BoxedVal Add(BoxedVal other)
{
BoxedInt i = (BoxedInt)other;
return new BoxedInt(Value + i.Value);
}
@Override
public boolean LessThan(BoxedVal other)
{
BoxedInt i = (BoxedInt)other;
return Value < i.Value;
}
@Override
public boolean GreaterThan(BoxedVal other)
{
BoxedInt i = (BoxedInt)other;
return Value > i.Value;
}
}
public class BoxingTest {
private static int Fib(int nn)
{
BoxedVal one = new BoxedInt(1);
BoxedVal a = one;
BoxedVal b = one;
BoxedVal n = new BoxedInt(nn);
BoxedVal thousand = new BoxedInt(1000);
for (BoxedVal i = new BoxedInt(2); i.LessThan(n); i = i.Add(one))
{
BoxedVal c = a.Add(b);
a = b;
b = c;
if (b.GreaterThan(thousand))
{
a = one;
b = one;
}
}
return ((BoxedInt)b).Value;
}
public static void main(String[] args) {
int times = 5;
int n = 20000000;
long total = 0;
for (int i = 0; i<times;i++){
long start = System.currentTimeMillis();
int val = Fib(n);
long dt = System.currentTimeMillis() - start;
total+= dt;
System.out.println(val);
System.out.println("Elapsed: "+dt+" ms");
}
System.out.println("Average: "+(total/times)+" ms");
}
}
我遇到的情况是,我的Windows机器上的Java(1.7)版本比.NET(4.5)快<2> 。考虑到GC既是世代的又是强烈优化的,我认为这是一个很大的差异,我在网上找不到任何解释它的东西。
我希望我的.NET代码在这种情况下像Java那样快速执行。我可以这样做吗? 有人有想法吗?是否有任何文章/博客文章可以帮助我?
答案 0 :(得分:3)
在我的环境中,Java 1.8.0.25比.NET 4.5.1(x64都快)快三倍。 你得到了更近的改变&#34; as&#34;表达式到标准转换。像
BoxedInt i = other as BoxedInt;
到
BoxedInt i = (BoxedInt)other;
添加一些像
这样的结构int Value;
int[] Dummy;
public BoxedInt(int value)
{
Value = value;
Dummy = new int[10];
}
两者都使Java比.NET慢8倍 这种微观基准测试显示了有趣的结果,但在许多方面都不可行。
答案 1 :(得分:1)
在这种情况下,使用Server GC无需更改,因为只有一个线程正在运行。值类型也是不好的选择。 由于BoxedInt.Add()中的BoxedInt结构太多,因此值类型比原始类型慢约40%。
在这种情况下,只有Java和.NET之间的差异才是对象构造的代价。 如果您使用“只有一个整数”作为一个类并花费大量时间在其上,请使用Java。
但这只是微观基准。如前所述,只添加一个整数数组引用会使Java变慢。
答案 2 :(得分:0)
有很多方法可以解决这种情况。在不更改代码的情况下,启用“服务器”垃圾收集器应该稍微缩小差距:
另一种方法是在C#代码中小心使用值类型而不是引用类型,以避免完全分配,即使您正在使用值的许多“实例”。这并不总是正确的方法,但对于某些类型的问题(特别是上面显示的情况),值类型可以导致.NET代码比等效的Java代码执行许多倍的速度