当前位置:首页 > 科技  > 软件

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

来源: 责编: 时间:2023-10-06 19:20:32 196观看
导读大家在平时开发中大多都会遵循接口编程,这样就可以方便实现依赖注入也方便实现多态等各种小技巧,但这种是以牺牲性能为代价换取代码的灵活性,万物皆有阴阳,看你的应用场景进行取舍。一:背景1. 缘由在项目的性能改造中,发现

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

一:背景

1. 缘由

在项目的性能改造中,发现很多方法签名的返回值都是采用IEnumerable接口,比如下面这段代码:UZp28资讯网——每日最新资讯28at.com

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();        }

2. 有什么问题

这段代码乍一看也没啥什么性能问题,foreach迭代天经地义,这个还能怎么优化???UZp28资讯网——每日最新资讯28at.com

<1> 从MSIL中寻找问题

首先我们尽可能把原貌还原出来,简化后的MSIL如下。UZp28资讯网——每日最新资讯28at.com

.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迭代数组嘛?至于搞的这么复杂嘛?这样在大数据下怎么快的起来?UZp28资讯网——每日最新资讯28at.com

还有一个奇葩的事,如果你仔细观察IL代码,比如这句:[mscorlib]System.Collections.Generic.IEnumerable``1<int32>::GetEnumerator(), 这个GetEnumerator前面是接口IEnumerable,正常情况下应该是具体迭代类吧,按理说应该会调用Array的GetEnumerator方法,如下所示。UZp28资讯网——每日最新资讯28at.com

[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中发现的第二个问题我特别好奇,

本文链接:http://www.28at.com/showinfo-26-12145-0.html面向接口编程,你考虑过性能吗?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: SpringBoot项目部署轻松变Docker,原来只需这几步!

下一篇: 数据安全之道:Java加密技术保护MySQL数据库

标签:
  • 热门焦点
Top