Csharp/C#教程:使用具体类型而不是界面是否更好的性能?分享


使用具体类型而不是界面是否更好的性能?

我已经遇到一些规则(建议)使用具体的ListDictionary而不是IListIDictionary ,因为示例测试显示通过接口访问速度相当慢。 例如,向列表中添加10000个值然后在列表上执行10亿次Count表明,通过接口执行此操作比通过具体类执行它慢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 } 

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 } 

这里没有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(); } } } 

输出:

 Interface: 4861 Concrete: 4236 

这在您的应用程序中确实是一个问题,接口可以使您的代码更好,更容易重用/维护

如果你真的需要提高性能,首先尝试改进算法,例如,你真的需要计算10亿次元素吗? 你不能把计数存储在某个地方,并有一些标志,表明元素已经改变,你需要重新计算它?

话虽如此,改变为通用接口的性能影响问题可以解决接口的性能问题

在未优化的DEBUG模式下,使用.Net 3.5,Visual Stusio 2008的RELEASE模式没有明显的性能差异。

 Debug: List test, ms: 1234.375 IList test, ms: 1218.75 Release: List test, ms: 609.375 IList test, ms: 968.75 

测试代码:

 List list = new List(); var start = DateTime.Now; for (int i = 0; i < 50000000; i++) list.Add(i); for (int i = 0; i < 50000000; i++) list[i] = 0; var span = DateTime.Now - start; Console.WriteLine("List test, ms: {0}", span.TotalMilliseconds); IList ilist = new List(); start = DateTime.Now; for (int i = 0; i < 50000000; i++) ilist.Add(i); for (int i = 0; i < 50000000; i++) ilist[i] = 0; span = DateTime.Now - start; Console.WriteLine("IList test, ms: {0}", span.TotalMilliseconds); 

这是我用来查看差异的测试代码:

 using System; using System.Collections.Generic; using System.Diagnostics; public class test1 { static void Main(string[] args) { Stopwatch sw = new Stopwatch(); const int NUM_ITEMS = 10000; const int NUM_LOOPS2 = 1000000000; List lst = new List(NUM_ITEMS); IList ilst = lst; for (int i = 0; i < NUM_ITEMS; i++) { lst.Add(i); } int count = 0; sw.Reset(); //GC.Collect(); sw.Start(); for (int i = 0; i < NUM_LOOPS2; i++) { count = lst.Count; } sw.Stop(); Console.Out.WriteLine("Took " + (sw.ElapsedMilliseconds) + "ms - 1."); sw.Reset(); //GC.Collect(); sw.Start(); for (int i = 0; i < NUM_LOOPS2; i++) { count = ilst.Count; } sw.Stop(); Console.Out.WriteLine("Took " + (sw.ElapsedMilliseconds) + "ms - 2."); } } 

请注意,垃圾收集似乎不会影响此测试。

上述就是C#学习教程:使用具体类型而不是界面是否更好的性能?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注---计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/992429.html

(0)
上一篇 2021年12月24日
下一篇 2021年12月24日

精彩推荐