2010-08-11 55 views
0

我有一個類通過一些擴展方法修改數據。爲了調試性能,我創建了一些粗略的調試代碼,多次使用相同的數據對同一方法進行多次調用。我發現,在循環中第一次執行計算所需的時間比後續調用所需的時間要長得多。首次調用擴展方法比後續調用要慢

例如,對於一小部分數據,似乎需要大約5秒來完成計算,而每個後續的調用是一秒左右。

感謝, WTS

的代碼看起來是這樣的:

測試代碼

void TestCode() 
{ 
    for (int i = 0; i < iterationsPerLoop; i++) 
    { 
     DateTime startTime = DateTime.Now; 

     // The test is actually being done in a BackgroundWorker 
     dispatcher.Invoke(DispatcherPriority.Normal, 
          (Action)(() => this.PropertyCausingCodeToRun = "Run"; 
     while (this.WaitForSomeCondition) 
      Thread.Sleep(125); 
     DateTime endTime = DateTime.Now; 

     double result = endTime.Subtract(startTime).TotalSeconds; 
    } 
} 

方法,其中擴展方法稱爲

private static List<ObservableItem> GetAvailableItems(MyObject myObject) 
{ 
    var items = new List<ObservableItem>(myObject.Items.ToList()); 
    var selectedItems = items.OrderByDescending(item => item.ASortableProperty) 
          .SetItemIsAvailable(false) 
          .SetItemPriority() 
          .OrderByDescending(item => item.Priority) 
          .Where(item => item.Priority > 0) 
          .SetItemIsAvailable(true) 
          .OrderBy(item => item.Date); 

    return selectedItems.ToList(); 
} 

擴展方法(ObservableItems在不同的線程都創造)

static class MyExtensionMethods 
{ 
    public static IEnumerable<T> SetItemIsAvailable<T>(this IEnumerable<T> sourceList, 
      Boolean isAvailable) where T : ObservableItem 
    { 
     Action<T> setAvailable = i => i.IsAvailable = isAvailable; 

     List<DispatcherOperation> invokeResults = new List<DispatcherOperation>(); 

     foreach (var item in sourceList) 
     { 
      invokeResults.Add(
       item.ItemDispatcher.BeginInvoke(setAvailable , new object[] { item })); 
     } 

     invokeResults.ForEach(ir => ir.Wait()); 
     return sourceList; 
    } 

    public static IEnumerable<T> SetItemPriority<T>(this IEnumerable<T> sourceList) where T : ObservableItem 
    { 
     Action<T, double> setPriority = new Action<T, double>((item, priority) => 
      { 
       item.Priority = priority; 
      }); 

     List<DispatcherOperation> invokeResults = new List<DispatcherOperation>(); 

     foreach (var item in sourceList) 
     { 
      double priority = ......; // Some set of calculations 

      invokeResults.Add(
       item.ItemDispatcher.BeginInvoke(setPriority, 
          new object[] { asset, priority })); 
     } 

     invokeResults.ForEach(ir => ir.Wait()); 
     return sourceList; 
    } 
} 
+1

這裏有很多*包括各種等待和睡眠。你應該包括診斷來確定時間到底在哪裏。 – 2010-08-11 15:39:40

回答

4

大多數情況下,在第一時間方法被調用時,有一個與JIT編譯時間相關的一些開銷。這會產生影響(儘管很可能不會那麼多)。

然而,看着你的代碼,你花費了大量的時間等待異步調用通過調度程序編組到UI。這將對您的整體表現產生巨大的影響,並且會以這種方式慢下來。

我建議在一次調度中完成所有操作,並使用Invoke而不是BeginInvoke。每個項目不要編組一條消息,只需編組包含通過項目的foreach循環的單個委託。

這將顯着加快。

+0

謝謝。我相信我理解你所說的大部分內容,但我不確定「編組單個委託,包括通過項目的foreach循環」的實現細節。例如:firstItem.Dispatcher.Invoke(new Action(()=> foreach(var item in sourceList){item.IsAvailable = isAvailable;}}),null); – 2010-08-11 17:51:52

0

真正的問題,正如我所知道的,是由最初被調用來對項目進行排序的屬性(甚至在調用擴展方法之前)引起的。

該屬性是以下形式:

public Double ASortableProperty 
{ 
    get 
    { 
     if (mASortableProperty.HasValue) 
     { 
      return mASortableProperty.Value; 
     } 
     mASortableProperty = this.TryGetDoubleValue(...); 
     return (mASortableProperty.HasValue ? mASortableProperty.Value : 0); 
    } 
} 

因此,第一次通過此循環,對值沒有從數據庫初始化,並且成本是檢索這些值,之前的排序可以採取地點。