大家應該都知道Int32.Parse()是不安全,但有時可能會有僥幸心理,而我正是在這樣的心理驅使下,這么干了。相關場景簡化處理后的代碼,如下。
List<BookInfo> bookLst = new List<BookInfo>(); for (var i = 0; i < 100000000; i++) { bookLst.Add(new BookInfo() { Num = i.ToString() }); } //原有寫法 var finalBookLst1= bookLst.Where(p => Int32.Parse(p.Num) > 10).ToList(); public class BookInfo { public string Num { get; set; } }
很顯然,在linq的where條件之中,直接進行類型轉換是不安全的,基於此我們需要對這段代碼進行優化。
既然是對集合進行操作,那么我們可以使用for循環,來替代原有的where條件,因此便有了下面一段代碼。
var finalBookLst2= new List<BookInfo>(); for (var j = 0; j < bookLst.Count; j++) { int num1; Int32.TryParse(bookLst[j].Num,out num1); if (num1 > 10) finalBookLst2.Add(bookLst[j]); }
在上述代碼中,我們直接遍歷集合中的每一個對象,對其進行業務判斷后,將滿足條件的對象加入到預期結果的集合之中,最后我們便得到了最終的結果。
用for循環寫完之后,我的第一想法就是這多low呀,性能得多差呀。於是乎經過了一番百度,我們的第二個方案便產生了。
ConcurrentBag<BookInfo> finalBookLst3 = new ConcurrentBag<BookInfo>(); Parallel.For(0,bookLst.Count,(num)=> { int num2; Int32.TryParse(bookLst[num].Num,out num2); if (num2 > 10) finalBookLst3.Add(bookLst[num]); });
Parallel主要用於任務的並行執行,在上面的示例中,我們將我們業務判斷通過Parallel並行執行,希望能夠優化響應時間。但是,悲催的是,使用Parallel的方案更加耗時。
從以上示例可以看出,並行執行並不一定比串行執行效率高,因為並行執行是有額外開銷。同時需要支出的是,List是線程不安全的,因此我們使用ConcurrentBag<T>來保存處理結果。
而對於bookLst的訪問,由於不存在資源競爭,所以是安全。
木得辦法,由於Parallel性能太差,我們是要舍棄這種方案的,想要替代for循環還得另尋它法,最后便有了如下代碼的產生,這也是我們最終選擇的方案。
private static bool CheckNum(BookInfo bookInfo) { int num; Int32.TryParse(bookInfo.Num, out num); if (num > 10) return true; else return false; } var finalBookLst4 = bookLst.Where(new Func<BookInfo,bool>(CheckNum)).ToList();