大家在平时开发中大多都会遵循接口编程,这样就可以方便实现依赖注入也方便实现多态等各种小技巧,但这种是以牺牲性能为代价换取代码的灵活性,万物皆有阴阳,看你的应用场景进行取舍。
在项目的性能改造中,发现很多方法签名的返回值都是采用ienumerable接口,比如下面这段代码:
public static void main(string[] args) { var list = gethasemailcustomeridlist(); foreach (var item in list){} console.readline(); } public static ienumerable<int> gethasemailcustomeridlist() { return enumerable.range(1, 5000000).toarray(); }
这段代码乍一看也没啥什么性能问题,foreach迭代天经地义,这个还能怎么优化???
首先我们尽可能把原貌还原出来,简化后的msil如下。
.method public hidebysig static void main ( string[] args ) cil managed { il_0009: callvirt instance class [mscorlib]system.collections.generic.ienumerator`1<!0> class [mscorlib]system.collections.generic.ienumerable`1<int32>::getenumerator() il_000e: stloc.1 .try { il_000f: br.s il_001a // loop start (head: il_001a) il_0011: ldloc.1 il_0012: callvirt instance !0 class [mscorlib]system.collections.generic.ienumerator`1<int32>::get_current() il_0017: stloc.2 il_0018: nop il_0019: nop il_001a: ldloc.1 il_001b: callvirt instance bool [mscorlib]system.collections.ienumerator::movenext() il_0020: brtrue.s il_0011 // end loop il_0022: leave.s il_002f } // end .try finally { il_0024: ldloc.1 il_0025: brfalse.s il_002e il_0027: ldloc.1 il_0028: callvirt instance void [mscorlib]system.idisposable::dispose() il_002d: nop il_002e: endfinally } // end handler il_002f: ret } // end of method program::main
从il中看到了标准的get_current,movenext,dispose
还有一个try,finally
,一下子多了这么多方法和关键词,不就是一个简单的foreach迭代数组嘛? 至于搞的这么复杂嘛?这样在大数据下怎么快的起来?
还有一个奇葩的事,如果你仔细观察il代码,比如这句:[mscorlib]system.collections.generic.ienumerable``1<int32>::getenumerator()
, 这个getenumerator前面是接口ienumerable,正常情况下应该是具体迭代类吧,按理说应该会调用array的getenumerator方法,如下所示。
[serializable] [comvisible(true)] [__dynamicallyinvokable] public abstract class array : icloneable, ilist, icollection, ienumerable, istructuralcomparable, istructuralequatable { [__dynamicallyinvokable] public ienumerator getenumerator() { int lowerbound = getlowerbound(0); if (rank == 1 && lowerbound == 0) { return new szarrayenumerator(this); } return new arrayenumerator(this, lowerbound, length); } }
il中发现的第二个问题我特别好奇,
如对本文有疑问, 点击进行留言回复!!
使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)
C#实现获取本地内网(局域网)和外网(公网)IP地址的方法分析
网友评论