有些事情,同樣在使用 TPL 時也需要避免。第一件事情就是使用記憶體的 allocation。
原因
記憶體的 allocation 會導致 GC,記憶體的回收變成的一項負擔。
解決方法1: 使用 stack,避免GC。
範例程式如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace TPL_2 { class Program { static void Main(string[] args) { Console.WriteLine("Sequence"); Console.WriteLine(Time(GoSeq)); Console.WriteLine("Parallel, using heap"); Console.WriteLine(Time(GoPalHeap)); Console.WriteLine("Parallel, using stack"); Console.WriteLine(Time(GoPalStack)); } private static void GoSeq() { var q = (from i in Enumerable.Range(1, 20000000) select new { Value = i }).Max(i => i.Value); Console.WriteLine(q); } //anonymous type, 會使用 heap。導致GC 回收記憶體,效能較差 private static void GoPalHeap() { var q = (from i in ParallelEnumerable.Range(1, 20000000) select new { Value = i }).Max(i => i.Value); Console.WriteLine(q); } //struct, 會使用 stack,效能較快 private static void GoPalStack() { var q = (from i in ParallelEnumerable.Range(1, 20000000) select new MyClass { Value = i }).Max(i => i.Value); Console.WriteLine(q); } struct MyClass { public int Value; } static TimeSpan Time(Action a) { Stopwatch w = Stopwatch.StartNew(); a(); return w.Elapsed; } } }執行結果
想不到吧!使用 Heap 反而使得 TPL 執行效果比不使用更差。改使用 struct 後就變快了。
解決方法2: 使用 Server GC
第二個方法是啟用 Server GC (伺服器記憶體回收),見<gcServer> 項目。簡單的說,使用這個方法,會讓CPU 的每個 Core 有獨立的 GC,因此回收的效能變快了。
.net framework 預設使用 workstation (工作站)的方式回收記憶體,也就是只有一個 GC。使用預設的 workstation 方式時, GC 必須考慮 multi-core 的 concurrency 問題,因此回收的效能較差。
我們加上一個 app.config ,如下
<?xml version="1.0" encoding="utf-8" ?> <configuration> <runtime> <gcServer enabled="true" /> </runtime> </configuration>
執行結果
由結果得知,加上設 gcServer 的設定,雖然仍然使用了 heap,速度還是變快了,但無法與使用 stack相比。
沒有留言:
張貼留言