Pie*_*kel 7 .net c# performance
我有一个struct包含单个object字段的对象,可以更轻松地处理对象.我想测试性能(我预计会有一些降级),但是我得到了非常令人惊讶的结果.实际版本struct更快:
没有盒子:8.08秒
带框:7.76秒
这怎么可能?
下面是重现结果的完整测试代码.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication68
{
partial class Program
{
private const int Iterations = 100000000;
static void Main(string[] args)
{
// Force JIT compilation.
TimeWithoutBox(new MyObject());
TimeWithoutBox(7);
TimeBox(new MyObject());
TimeBox(7);
// The tests.
var withoutBox = new TimeSpan();
var box = new TimeSpan();
for (int i = 0; i < 10; i++)
{
withoutBox += TimeWithoutBox(new MyObject());
withoutBox += TimeWithoutBox(7);
box += TimeBox(new MyObject());
box += TimeBox(7);
}
Console.WriteLine("Without box: " + withoutBox);
Console.WriteLine("With box: " + box);
Console.ReadLine();
}
private static TimeSpan TimeBox(object value)
{
var box = new MyBox(value);
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
TestBox(box);
}
return stopwatch.Elapsed;
}
private static TimeSpan TimeWithoutBox(object value)
{
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
TestWithoutBox(value);
}
return stopwatch.Elapsed;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void TestBox(MyBox box)
{
if (box.IsDouble)
TakeDouble((double)box.Value);
else if (box.IsObject)
TakeObject((MyObject)box.Value);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void TestWithoutBox(object box)
{
if (box.GetType() == typeof(double))
TakeDouble((double)box);
else if (box.GetType() == typeof(MyObject))
TakeObject((MyObject)box);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void TakeDouble(double value)
{
// Empty method to force consuming the cast.
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void TakeObject(MyObject value)
{
// Empty method to force consuming the cast.
}
}
struct MyBox
{
private readonly object _value;
public object Value
{
get { return _value; }
}
public MyBox(object value)
{
_value = value;
}
public bool IsDouble
{
get { return _value.GetType() == typeof(double); }
}
public bool IsObject
{
get { return _value.GetType() == typeof(MyObject); }
}
}
class MyObject
{
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
我已经改变了IsDouble和IsObject测试,使其具有与其他测试相同的语句.我重新执行了应用程序,结果时间完全相同.
EDIT2:
此代码使用版本编译32位进行测试,未附加调试器; .NET 4.5和Visual Studio 2012.针对64位进行编译会产生截然不同的结果; 在我的机器上:
没有方框:8.23秒
带框:16.99秒
我复制了确切的代码,在没有调试器的情况下(都很重要!)在 x64 上运行它。结果:
Without box: 00:00:07.9650541
With box: 00:00:16.0958162
Run Code Online (Sandbox Code Playgroud)
将测试更改为:
[MethodImpl(MethodImplOptions.NoInlining)]
private static void TestBox(MyBox box)
{
if (box.Value.GetType() == typeof(double))
TakeDouble((double)box.Value);
else if (box.Value.GetType() == typeof(MyObject))
TakeObject((MyObject)box.Value);
}
Run Code Online (Sandbox Code Playgroud)
使运行时间几乎相等:
Without box: 00:00:07.9488281
With box: 00:00:08.6084029
Run Code Online (Sandbox Code Playgroud)
为什么?因为 JIT 决定不内联IsDouble,而手动内联会有所帮助。这很奇怪,因为它是一个很小的函数。第call13 行就是这个调用。

现在为什么仍然存在一些性能差异?.NET JIT 并不是最好的编译器...可能有些指令略有不同。通过对比两个版本的反汇编就可以知道。我没有时间这样做,因为我预计这种差异非常无趣。
我希望 C 编译器能做到这一点。object该结构的行为应该类似于它包含的单个成员。小方法应该内联。使用当今的编译器技术这绝对是可行的。希望下一代 JIT 和 NGEN 能够做到这一点。目前正在开发一个新的 JIT (RyuJIT),他们正在将优化从 VC 后端转移到 NGEN(最近宣布)。
| 归档时间: |
|
| 查看次数: |
200 次 |
| 最近记录: |