2015-09-24 73 views
2

我正在評估C#.NET Web應用程序中的性能問題,並將瓶頸追蹤到鏈式lambda表達式。我想完全刪除lambda表達式,所以我可以評估鏈中每個步驟的性能,但我對lambda表達式相對較新。有沒有人對如何將第二個lambda表達式重構爲更傳統的代碼有任何想法,以便每個步驟或動作都可以跟蹤?消除.net lambda表達式

IEnumerable<OurPerformance> validPerformances = package.TimeFilteredValidPerformances(visitDateAndTime); 

IEnumerable<WebPerformance> webPerformances = performanceGroup.RegularNonPassedPerformances 
      .Where(performance => validPerformances.Select(perf => perf.PerformanceId).Contains(performance.PerformanceId))     
      .Select(performance => 
       new WebPerformance 
       { 
        Date = performance.PerformanceDate.ToJavaScriptDateString(), 
        PerformanceId = performance.PerformanceId, 
        Title = performance.UserFriendlyTitle, 
        ProductionSeasonId = performance.ProductionSeasonId, 
        AvailableCount = performance.AvailableCount 
       }); 

**IEnumerable<WebProduction> webProductions = webPerformances 
      .GroupBy(performance => performance.ProductionSeasonId) 
      .ToDictionary(grouping => SheddProduction.GetOurProduction(grouping.Key), grouping => grouping.ToList()) 
      .Select(perfsByProduction => 
       new WebProduction 
       { 
        ProductionSeasonId = perfsByProduction.Key.ProductionSeasonNumber, 
        Duration = perfsByProduction.Key.Duration, 
        Title = perfsByProduction.Key.UserFriendlyTitle, 
        Synopsis = perfsByProduction.Key.UserFriendlySynopsis, 
        ThumbnailImage = perfsByProduction.Key.PreviewImage, 
        Performances = perfsByProduction.Value 
       });** 
+0

爲什麼你要同時使用ToDictionary和GroupBy? 「ToDictionary」似乎不必要。 – dbc

回答

1

它實際上很簡單,可以將其分解爲更小的片段,這些片段更明顯地轉換爲「傳統」代碼。只是每個LINQ表達式的結果存儲在這樣的局部變量:

var groupedWebPerformances = webPerformances.GroupBy(performance => performance.ProductionSeasonId); 
var webPerformancesDictionary = groupedWebPerformances .ToDictionary(grouping => SheddProduction.GetOurProduction(grouping.Key), grouping => grouping.ToList()); 
IEnumerable<WebProduction> webProductions = webPerformancesDictionary.Select(perfsByProduction => 
       new WebProduction 
       { 
        ProductionSeasonId = perfsByProduction.Key.ProductionSeasonNumber, 
        Duration = perfsByProduction.Key.Duration, 
        Title = perfsByProduction.Key.UserFriendlyTitle, 
        Synopsis = perfsByProduction.Key.UserFriendlySynopsis, 
        ThumbnailImage = perfsByProduction.Key.PreviewImage, 
        Performances = perfsByProduction.Value 
       }); 

話雖這麼說,你的表現的問題是,你使用IEnumerable無處不在。 IEnumerable可能會在每次使用它們時重新評估(取決於底層類型是什麼),所以validPerformances正在針對RegularNonPassedPerformances中的每個項目重新評估一次,並且webPerformances中的每個項目都未被評估,直到整個枚舉被強制爲評估,因此性能問題似乎是後來卻是最有可能在這裏:

validPerformances.Select(perf => perf.PerformanceId).Contains(performance.PerformanceId) 

確保你強迫所有可枚舉通過對他們做了ToList來評估一個單一的時間,他們都是這樣創建時:

List<OurPerformance> validPerformances = package.TimeFilteredValidPerformances(visitDateAndTime).ToList(); 

List<WebPerformance> webPerformances = performanceGroup.RegularNonPassedPerformances 
      .Where(performance => validPerformances.Select(perf => perf.PerformanceId).Contains(performance.PerformanceId))     
      .Select(performance => 
       new WebPerformance 
       { 
        Date = performance.PerformanceDate.ToJavaScriptDateString(), 
        PerformanceId = performance.PerformanceId, 
        Title = performance.UserFriendlyTitle, 
        ProductionSeasonId = performance.ProductionSeasonId, 
        AvailableCount = performance.AvailableCount 
       }) 
      .ToList(); 

List<WebProduction> webProductions = webPerformances 
      .GroupBy(performance => performance.ProductionSeasonId) 
      .ToDictionary(grouping => SheddProduction.GetOurProduction(grouping.Key), grouping => grouping.ToList()) 
      .Select(perfsByProduction => 
       new WebProduction 
       { 
        ProductionSeasonId = perfsByProduction.Key.ProductionSeasonNumber, 
        Duration = perfsByProduction.Key.Duration, 
        Title = perfsByProduction.Key.UserFriendlyTitle, 
        Synopsis = perfsByProduction.Key.UserFriendlySynopsis, 
        ThumbnailImage = perfsByProduction.Key.PreviewImage, 
        Performances = perfsByProduction.Value 
       }) 
      .ToList(); 
+0

關於linq和lazy-evaluation的一個很好的入門書籍:http://blogs.msdn.com/b/ericwhite/archive/2006/10/04/lazy-evaluation-_2800_and-in-contrast_2c00_-eager-evaluation_2900_.aspx – mydogisbox

+0

I有這個確切的例子,但你擊敗了我。 – DVK

+0

@DVK比DVK的速度快! – mydogisbox

2

我不能建議任何算法來排除lambda表達式,但我有另一個建議。嘗試使用List for webPerformances而不是IEnumerable集合。 調用ToList()獲取List web性能。在這種情況下,第二個lambda表達式將與列表一起工作,並且不會重新評估IEnumerable集合。

1

這裏是羊肉你的第二個lambda表達式的-重構爲「傳統」代碼:

IEnumerable<IGrouping<string, WebProduction>> groupedPerformances 
    = webPerformances.GroupBy(performance => performance.ProductionSeasonId); 

var dictionary = new Dictionary<string, List<WebProduction>>(); 
foreach (IGrouping<string, WebProduction> grouping in groupedPerformances) 
{ 
    var group = new List<WebProduction>(); 
    foreach (WebProduction webProduction in grouping) 
     group.Add(webProduction); 

    dictionary.Add(grouping.Key, group); 
} 

var result = new List<WebProduction>(); 
foreach (KeyValuePair<string, List<WebProduction>> item in dictionary) 
{ 
    var wp = new WebProduction 
    { 
     ProductionSeasonId = perfsByProduction.Key.ProductionSeasonNumber, 
     Duration = perfsByProduction.Key.Duration, 
     Title = perfsByProduction.Key.UserFriendlyTitle, 
     Synopsis = perfsByProduction.Key.UserFriendlySynopsis, 
     ThumbnailImage = perfsByProduction.Key.PreviewImage, 
     Performances = perfsByProduction.Value 
    }; 
    result.Add(wp); 
} 

我不知道結果類型的SheddProduction.GetOurProduction方法,因此我做了細微的變化,但你可以得到的要點...