首頁  >  文章  >  後端開發  >  詳細介紹.NET中的效能改進

詳細介紹.NET中的效能改進

黄舟
黄舟原創
2017-03-09 15:41:551505瀏覽

  .NET 4.6中带来了一些与性能改进相关的CLR特性,这些特性中有一部分将会自动生效,而另外一些特性,例如SIMD与异步本地存储(Async Local Storage)则需要对编写应用的方式进行某些改动。

  SIMD

  Mono团队一直以他们对SIMD,即单指令流多数据流特性的支持引以为傲。SIMD是一种CPU指令集,它能够在同一时间对最多8个值进行同一操作。而随着.NET CLR版本4.6的推出,Windows开发者终于也能够使用这一特性了。

  为了实际观察一下SIMD的效果,可以参考一下这个示例。假设你需要通过c[i] = a[i] + b[i]这种形式对两个数组进行相加,以得到第三个数组。通过使用SIMD,你可以按照以下方式编写代码:

for (int i = 0; i < size; i += Vector.Count)
 {
     Vectorv = new Vector(A,i) + new Vector(B,i);
     v.CopyTo(C,i);
 }

  请注意这个循环是如何按Vectorbd43222e33876353aff11e13a7dc75f6.Count的取值进行递增的,根据CPU类型的不同,它的取值可能是4或是8。.NET JIT编译器将根据CPU的不同生成相应的代码,以4或8的值对数组进行批量相加。

  这种方式看起来有些繁琐,因此微软还提供了一系列辅助类,包括:

  • Matrix3x2 结构

  • Matrix4x4结构

  • Plane结构

  • Quaternion结构

  • Vector 类

  • Vector(T) 结构

  • Vector2结构

  • Vector3结构

  • Vector4结构

  程序集卸载

  恐怕大多数开发者都不知道这一点:.NET经常会对同一个程序集加载两次。发生这种情况的条件是.NET首先加载了某个程序集的IL版本,随后又加载了同一程序集的NGEN版本(即预编译版本)。这种方式对于物理内存来说是相当严重的浪费,尤其是对诸如Visual Studio这样的大型32位应用程序来说更为明显。

  而在.NET 4.6中,一旦CLR加载了某个程序集的NGEN版本,它会自动清空对应的IL版本所占用的内存。

  垃圾回收

  早先我们曾讨论过.NET 4.0中所引入的垃圾回收滞后时间模式,虽然这种方式比起让GC完全停止一段时间的做法要可靠许多,但对于许多GC场景来说,这种方式仍算不上完整。

  在.NET 4.6中,你将能够通过一种更精密的方式临时中止垃圾回收器的运作,新的TryStartNoGCRegion方法允许你指定在小对象以及大对象的堆中需要多少内存。

  如果出现内存不足的情况,运行时将会返回false,或是停止运行,直到通过GC清理得到足够的内存为止。你可以通过为TryStartNoGCRegion传入某个标记的方式控制这一行为,如果你成功地进入了某个无GC区域(在过程结束前不允许进行GC),那么在过程结束时必须调用EndNoGCRegion方法。

  在官方文档中并没有说明该方法是否是线程安全的,不过考虑到GC的工作原理,你应当尽量避免让两个进程同时尝试改变GC状态的做法。

  对于GC的另一项改进是它处理pinned对象(即一旦分配后不可移动位置的对象)的方式。虽然在文档中对此方面的描述有些语焉不详,但当你固定了某个对象的位置时,通常也会固定其相邻对象的位置。Rich Lander在文中写道:

GC将以一种更优化的方式处理pinned对象,因此GC能够将pinned对象周围的内存进行更有效地压缩。对于大量使用pin方式的大规模应用来说,这一改动将极大地改进应用的性能。

  GC对于如何使用较早的几代中的内存方面也体现出更好的智能性,Rich继续写道:

第1代对象升级为第2代对象的方式也得到了改进,以更有效地使用内存。在为某一代分配新的内存空间之前,GC会先尝试使用可用的空间。同时,在利用可用空间区域创建对象时使用了新的算法,使新分配的空间大小比起从前更接近于对象的大小。

  异步本地存储

  最后一项改进与性能并没有直接的关系,但通过有效的利用仍然能达到优化的效果。在异步API还没有流行起来的年代,开发者可以利用线程本地存储(TLS)缓存信息。TLS对于某个特定的线程来说就像是一种全局对象,这意味着你可以直接访问上下文信息并进行缓存,而无需显式地传递某种上下文对象。

  而在async/await模式中,線程本地存儲就變得毫無用武之地了。因為每次呼叫await的時候,都有可能跳到另一個執行緒。而且即使僥倖避開了這種情況,但其它代碼也有可能跳到你的線程中並幹擾TLS中的信息。

  新版的.NET引入了異步本地存儲(ALS)機制以解決這一問題,ALS在語義上等價於線程本地存儲,但它能夠隨著await的調用進行相應的跳轉。這項功能將透過AsyncLocal泛型類別實現,其內部將呼叫CallContext物件用於保存資料。


以上是詳細介紹.NET中的效能改進的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn