2015-06-30 82 views
1

我有一個處理零售促銷的C#程序集。它能夠在7秒內處理一次有1,288種合格產品的促銷活動。但是,如果它的任務是處理具有更多合格產品的促銷活動,那麼所花費的時間將與產品數量成指數增長。例如,29,962個產品的促銷需要7分鐘7秒,而77,350個產品的促銷需要39分鐘和7秒。理解VS性能分析

我一直在試圖確定程序集中是否有可以輕鬆優化的代碼。餘設置的組件處理中最大的促銷然後附着性能分析器到含處理(BizTalk主機實例)中,導致瞭如下報告:

enter image description here

這表明功能服用量最大的時間是「GetDataPromoLines」。這個函數包含簡單的字符串格式。它是從功能「MapForFF」以下循環調用:

foreach (var promoLine in promoLineChunk.PromoLines) 
{ 
    outputFile = outputFile + GetDataPromoLines(promoLine, promoLineNumber+1); 
    promoLineNumber++; 
} 

的promoLineChunck.PromoLines是描述推廣一類的List,它僅包含私人字符串 - 一個數據庫表中的每一列從中選擇促銷細節。在「GetDataPromoLines」功能的內容可以看出如下:

private string GetDataPromoLines(VW_BT_PROMOTIONSRECORDSELECT promoLine, int sequenceNumber) 
{ 
    StringBuilder sb = new StringBuilder(); 

    string seqNum = sequenceNumber.ToString().PadLeft(5, '0'); 
    string uniqueNumber = promoLine.CIMS_PROMO_NUMBER + seqNum; 

    sb.AppendLine(string.Format("PromoDiscount,\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\"", 
     uniqueNumber, 
     promoLine.CIMS_PROMO_NAME, 
     promoLine.TYPE, 
     promoLine.DESCRIPTION_, 
     promoLine.DISCOUNTLEVEL, 
     promoLine.COUPONNUMBERMIN, 
     promoLine.COUPONNUMBERMAX, 
     promoLine.COUPONNUMBERLENGTH 
     )); 

    sb.AppendLine(string.Format("ItemReq,\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\"", 
     "00001", 
     promoLine.IDENTITYTYPE, 
     promoLine.ITEMNUM, 
     promoLine.DIVISIONNUM, 
     promoLine.DEPARTMENTNUM, 
     promoLine.DEPTGROUPNUM, 
     promoLine.CLASSNUM, 
     promoLine.ITEMGROUPNUM, 
     promoLine.IR_QUANTITY 
     )); 

    sb.AppendLine(string.Format("TierDefinition,\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\"", 
     "00001", 
     promoLine.THRESHOLDTYPE, 
     promoLine.THRESHOLDQTY, 
     promoLine.THRESHOLDAMT, 
     promoLine.DISCTYPE, 
     promoLine.DISCPCT, 
     promoLine.DISCAMT, 
     promoLine.DISCAPPLIESTO, 
     promoLine.DISCQTY, 
     promoLine.ADDLINFO 
     )); 

    return sb.ToString(); 
} 

任何人都可以建議是什麼原因造成的時間來處理指數級增加?這與CLR拆箱有關嗎?

+1

指數衰減幾乎可以肯定算法,所以你應該看看,而不是擔心拳擊。 – Lee

+0

如果您只是調用GetDataPromoLines()而不將結果聯合到outputFile,那麼在性能方面會發生什麼? – Graffito

+0

使用'sb.AppendFormat'在'sb.AppendLine'上加上'string.Format'的情況下 –

回答

3

outputFile = outputFile + GetDataPromoLines(promoLine, promoLineNumber+1);

那是試圖通過附加的字符串來構建一個完整的輸出文件?你的Schlemiel。

對於這樣的情況下,你真的想用StringBuilder(甚至更好,直接輸出到使用StreamWriter什麼文件流):

StringBuilder outputFile; 

foreach (var promoLine in promoLineChunk.PromoLines) 
{ 
    outputFile.Append(GetDataPromoLines(promoLine, promoLineNumber+1)); 
    promoLineNumber++; 
} 

簡單追加的問題是,string是不可改變.NET - 每當你修改它時,它都被複制過來。對於輸出巨大文本文件的情況,這當然是非常昂貴的 - 你花費大部分時間來複制沒有改變的字符串部分。

同樣的方法,不要做sb.AppendLine(string.Format(...)); - 只需使用sb.AppendFormat。理想情況下,通過StringBuilder作爲參數,以避免必須複製這些行本身 - 儘管這應該是outputFile += ...旁邊的相對不重要的性能命中。

作爲一個側面提示,在解釋性能分析的結果時要小心 - 它通常會有微妙的誤導。在你的情況,我很確定你的問題不在GetDataPromoLines本身(雖然即使這可以改善,如上所示),但在outputFile += ...。只用最高的獨佔樣本來查看函數是不夠的。僅僅看熱門路徑也是不夠的,儘管這已經是一個巨大的提升,通常會引導你直奔需要關注的地方。此外,瞭解採樣和儀器之間的區別 - 採樣通常會導致您嘗試優化一種本身不是真正的性能問題的方法 - 相反,它不應該像以往那樣頻繁調用。不要使用profiler結果作爲眼罩 - 你仍然需要注意的意義

+0

我改變了在foreach中使用字符串生成器的呼叫(不知道我是如何錯過這個的!),結果是戲劇性的。處理最大促銷的時間從39分鐘7秒減少到35秒。謝謝你的幫助 :) –