use*_*095 15 .net c# performance
我遇到了一些规则(建议)使用混凝土List
和Dictionary
,而不是IList
和IDictionary
给予,显示通过该接口访问样本测试是相当慢一点.例如,将10000个值添加到列表然后Count
在列表上执行10亿次表示通过接口执行此操作比通过具体类执行它慢28倍.即,通过具体类需要80ms,通过界面需要2800ms,这表明它通过界面的速度非常慢.鉴于此,使用具体类是合理的.有没有理由说接口这么慢?(可能更多的是针对那些了解更多关于.net内部的人).
我认为如果你看一下反汇编就很明显了:
该IList
版本编译为:
for (int i = 0; i < 1000000000; i++)
0000003d xor edi,edi
{
count = lst.Count;
0000003f mov ecx,esi
00000041 call dword ptr ds:[00280024h]
00000047 mov ebx,eax
for (int i = 0; i < 1000000000; i++)
00000049 inc edi
0000004a cmp edi,3B9ACA00h
00000050 jl 0000003F
}
Run Code Online (Sandbox Code Playgroud)
访问权限IList.Count
被编译成call
指令.
List
另一方面,该版本内联:
for (int i = 0; i < 1000000000; i++)
0000003a xor edx,edx
0000003c mov eax,dword ptr [esi+0Ch]
0000003f mov esi,eax
00000041 inc edx
00000042 cmp edx,3B9ACA00h
00000048 jl 0000003F
}
Run Code Online (Sandbox Code Playgroud)
call
这里没有说明.只是循环中的mov,inc,cmp和jl指令.当然这更快.
但请记住:通常情况下,您正在对列表中的内容进行某些操作,而不仅仅是迭代它.这通常比单个函数调用花费更长的时间,因此调用接口方法很少会导致任何性能问题.
使用接口的主要原因是灵活性,关注点分离等.
所以我仍然建议在大多数情况下使用接口(不是全部,只是在适当的地方),并且只考虑在存在实际性能问题时切换到具体类.
并且,在没有GC.Collect()
和在发布模式下运行您的基准测试后,我得到96和560毫秒.差异很小.
你的表现测试显然是错误的.你正在测试很多不同的东西.首先GC.Collect
会触发终结器线程,它会影响其后运行的所有内容的性能.接下来,您不仅要测试调用接口方法所花费的时间,还要花费大量时间将数据复制到新数组(因为您正在创建大型数组)并收集它们! - 因此接口调用之间存在差异实例调用将完全迷失.
这是一个测试,我测试接口调用的原始性能开销.在Visual Studio外部以发布模式运行时:
public interface IMyInterface
{
void InterfaceMethod();
}
public class MyClass : IMyInterface
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void InterfaceMethod()
{
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void InstanceMethod()
{
}
}
class Program
{
static void Main(string[] args)
{
// JITting everyting:
MyClass c = new MyClass();
c.InstanceMethod();
c.InterfaceMethod();
TestInterface(c, 1);
TestConcrete(c, 1);
Stopwatch watch = Stopwatch.StartNew();
watch.Start();
var x = watch.ElapsedMilliseconds;
// Starting tests:
watch = Stopwatch.StartNew();
TestInterface(c, Int32.MaxValue - 2);
var ms = watch.ElapsedMilliseconds;
Console.WriteLine("Interface: " + ms);
watch = Stopwatch.StartNew();
TestConcrete(c, Int32.MaxValue - 2);
ms = watch.ElapsedMilliseconds;
Console.WriteLine("Concrete: " + ms);
}
static void TestInterface(IMyInterface iface, int iterations)
{
for (int i = 0; i < iterations; i++)
{
iface.InterfaceMethod();
}
}
static void TestConcrete(MyClass c, int iterations)
{
for (int i = 0; i < iterations; i++)
{
c.InstanceMethod();
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Interface: 4861
Concrete: 4236
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1297 次 |
最近记录: |