加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

.NET 性能优化的技巧

发布时间:2019-08-22 09:52:46 所属栏目:建站 来源:gejigeji
导读:最大化内联 内联是将要领体(method body)复制到挪用站点的技能,这样我们就可以停止跳转、参数转达和寄存器生涯/规复等繁琐进程。除了节减这些之外,内联照旧实现其他优化的须要前提。 不不外Roslyn(C#的编译器)没有内联代码,它是通过JIT实现的,大大都优

尽也许不要通过将值范例转换为引用范例来装箱值范例。这是常见的提议,但在API计划中必要思量一些身分。在Hagar中,可以接管值范例的接口和要领界说是通用的,以便它们可以专门用于准确范例并停止装箱/拆箱本钱。功效,没有热路径拳击。在某些环境下如故存在拳击,譬喻非常要领的字符串名目。可以通过对参数的显式. tostring()挪用来删除那些特定的装箱分派。

镌汰封锁分派

只分派闭包一次,并存储功效,就可供多次一再行使。譬喻,凡是将委托转达给ConcurrentDictionary. getoradd。与其将委托编写为内联lambda,还不如将define界说为类中的私有字段。下面是来自Hagar中可选ISerializable支持包的一个例子:

  1. private readonly Func<Type, Action<object, SerializationInfo, StreamingContext>> createConstructorDelegate; 
  2.  
  3. public ObjectSerializer(SerializationConstructorFactory constructorFactory) 
  4.     // Other parameters/statements omitted. 
  5.     this.createConstructorDelegate = constructorFactory.GetSerializationConstructorDelegate; 
  6.  
  7. // Later, on a hot code path: 
  8. var constructor = this.constructors.GetOrAdd(info.ObjectType, this.createConstructorDelegate); 

只管镌汰复制

.NET Core 2.0和2.1以及最近的C#版本,在删除数据复制进程的方面取得了相等大的前进。最值得留意的是Span,但在参数修饰符和只读布局中也值得一提。Span 是ref 布局仓库,而不是托管堆上分派。

行使Span来停止数组分派并停止数据复制

一个Span暗示恣意内存的相邻地区, 一个Span实例凡是用来生涯数组的元素或数组的一部门。

对付.NET Core来说,Span对付机能优化很是重要,它们行使优化的暗示来减小它们的巨细,这必要添加对内部指针的垃圾网络器的支持。内部指针是指向数组范畴内的托管引用,而不是只能指向第一个元素,因此必要一个包括数组偏移量的附加字段。有关Span的更多信息,请点此参考。

Hagar普及行使Span,由于它应承我们建设可用于较大缓冲区的分段试图。

通过ref转达布局以最小化仓库上的副本

Hagar行使两个首要布局,Reader 和Writer。这些布局包括几个字段,险些每次挪用城市转达给序列化或反序列化挪用路径。

在没有过问的环境下,行使这些布局举办的每个要领挪用城市带来很大的影响,由于每个挪用都必要将整个布局复制到仓库中。

我们可以通过将这些布局作为ref参数转达来停止副本的发生,其它,C#还支持行使ref this作为扩展要领的方针,这很是利便。据我所知,没有步伐确保特定的布局范例老是由ref转达,假如你不警惕在挪用的参数列表中省略了ref,这也许会导致运行错误。

停止掩护性拷贝(defensive copy)

Roslyn偶然必要做一些事变来担保一些说话稳固量,当布局存储在只读字段中时,编译器将插入一些指令,以停止复制该字段,然后再将其包括到任何能担保不会对其举办修改的操纵中。凡是,这意味着挪用在布局范例自己上界说的要领,由于将布局作为参数转达给在另一范例上界说的要领已经必要将布局复制到仓库上(除非通过ref或in转达)。

假如将 7.2 添加到csproj文件中,则可以将布局界说为只读布局(这是c# 7.2的说话特征),则可以停止掩护性拷贝。

偶然,假如你无法将其界说为只读布局,则最亏得其他不行变布局字段上省略readonly修饰符。

以Jon Skeet的NodaTime库为例,在这个示例中,Jon使大大都布局变为只读,因此可以或许将readonly修饰符添加到包括这些布局的字段中,而不会对机能发生负面影响。

镌汰分支和分支错误猜测

当代cpu依靠于长pipeline的指令,这些指令通过并发性举办处理赏罚。这涉及到CPU说明指令,以确定哪些指令不依靠于前面的指令,还涉及揣摩将回收哪些前提跳转语句。为此,CPU行使一个名为分支猜测器(branch predictor)的组件,该组件认真揣摩将回收哪个分支。它凡是通过读取和写入表中的条目来实现这一点,并按照前次执行前提跳转时产生的环境修改其猜测。

当猜测正确时,就会加速历程,不然就必要把猜测分支的指令排空,从头获取正确分支的指令进入pipeline继承执行。

以是加速历程的最好步伐就是镌汰分支和分支错误猜测,起首实行最小化分支数目,假如无法消除分支,请只管镌汰错误猜测率,这也许涉及行使排序数据或重构代码,可以用查找的步伐来取代分支猜测。

其他杂项提醒

1. 停止行使LINQ,LINQ在应用措施代码方面很精彩,但在库/框架代码中很少被用于路径。LINQ很难对JIT举办优化(IEnumerable..),并且倾向于多多分派。

2. 行使详细范例而不是接口或抽象范例,大概最常见的是,假如你在List 长举办迭代,最好不要先将该列表逼迫转换为IEnumerable (譬喻,通过行使LINQ或将其作为IEnumerable 参数转达给要领)。这样做的缘故起因是行使foreach列举列表行使非分派List .Enumerator布局,可是当它转换为IEnumerable 时,该布局必需被装箱到IEnumerator for foreach。

3. 反射在库代码中出格有效,缓存反射功效,思量行使IL或Roslyn为会见器天生委托,可能更好的要领是行使现有的库,如Microsoft.Extensions.ObjectMethodExecutor.Sources,Microsoft.Extensions.PropertyHelper.Sources或FastMember。

特定于库的优化

优化天生的代码

Hagar行使Roslyn为要序列化的POCO天生C#代码,这个C#代码在编译时包括在你的项目中。我们可以对天生的代码执行一些优化,以加速速率。

通过跳过对已知范例的编解码器查找来停止假造挪用

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读