面向接口编程,你考虑过性能吗?

网友投稿 270 2022-08-20

面向接口编程,你考虑过性能吗?

大家在平时开发中大多都会遵循接口编程,这样就可以方便实现依赖注入也方便实现多态等各种小技巧,但这种是以牺牲性能为代价换取代码的灵活性,万物皆有阴阳,看你的应用场景进行取舍。

一:背景

1. 缘由

在项目的性能改造中,发现很多方法签名的返回值都是采用IEnumerable接口,比如下面这段代码:

public static void Main(string[] args)

{

var list = GetHasEmailCustomerIDList();

foreach (var item in list){}

Console.ReadLine();

}

public static IEnumerable GetHasEmailCustomerIDList()

{

return Enumerable.Range(1, 5000000).ToArray();

}

2. 有什么问题

这段代码乍一看也没啥什么性能问题,foreach迭代天经地义,这个还能怎么优化???

<1> 从MSIL中寻找问题

首先我们尽可能把原貌还原出来,简化后的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::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::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::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);

}

}

<2> 从windbg中寻找问题

IL中发现的第二个问题我特别好奇,

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:C# 基础知识系列-13 常见类库(三)(c罗)
下一篇:C#串口通讯,复制粘贴就可用,仅仅介绍怎样最快的搭建一个串口通讯,异常拦(cp是什么意思?)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~