2013-05-14 70 views
0

我有一個程序,它根據結果是以某種方式對返回的結果集進行顏色編碼。由於對結果進行顏色編碼需要很長時間(目前正在使用Regex和RichTextBox.Select + .SelectionColor完成),所以我在400個結果處切斷了顏色編碼。在這個數字大約需要20秒,這是我認爲合理的最大時間。Parallel.ForEach和Regex沒有性能提升嗎?

爲了提高性能,我重新編寫了正則表達式部分,使用Parallel.ForEach循環遍歷MatchCollection,但時間大約相同(18-19秒vs 20)!僅僅是不適合並行編程的工作呢?我應該嘗試不同的東西嗎?任何建議是受歡迎的。謝謝!

PS:以爲有點奇怪我的CPU利用率從來沒有下降到14%左右,無論有無Parallel.ForEach。

代碼

MatchCollection startMatches = Regex.Matches(tempRTB.Text, startPattern); 

object locker = new object(); 
System.Threading.Tasks.Parallel.ForEach(startMatches.Cast<Match>(), m => 
{ 
    int i = 0; 
    foreach (Group g in m.Groups) 
    { 
     if (i > 0 && i < 5 && g.Length > 0) 
     { 
      tempRTB.Invoke(new Func<bool>(
       delegate 
       { 
        lock (locker) 
        { 
         tempRTB.Select(g.Index, g.Length); 
         if ((i & 1) == 0) // Even number 
          tempRTB.SelectionColor = Namespace.Properties.Settings.Default.ValueColor; 
         else    // Odd number 
          tempRTB.SelectionColor = Namespace.Properties.Settings.Default.AttributeColor; 
         return true; 
        } 
       })); 
     } 
     else if (i == 5 && g.Length > 0) 
     { 
      var result = tempRTB.Invoke(new Func<string>(
       delegate 
       { 
        lock (locker) 
        { 
         return tempRTB.Text.Substring(g.Index, g.Length); 
        } 
       })); 

      MatchCollection subMatches = Regex.Matches((string)result, pattern); 

      foreach (Match subMatch in subMatches) 
      { 
       int j = 0; 
       foreach (Group subGroup in subMatch.Groups) 
       { 
        if (j > 0 && subGroup.Length > 0) 
        { 
         tempRTB.Invoke(new Func<bool>(
          delegate 
          { 
           lock (locker) 
           { 
            tempRTB.Select(g.Index + subGroup.Index, subGroup.Length); 
            if ((j & 1) == 0) // Even number 
             tempRTB.SelectionColor = Namespace.Properties.Settings.Default.ValueColor; 
            else    // Odd number 
             tempRTB.SelectionColor = Namespace.Properties.Settings.Default.AttributeColor; 
            return true; 
           } 
          })); 
        } 
        j++; 
       } 
      } 
     } 
     i++; 
    } 
}); 
+0

14%的利用率聽起來像是使用超線程技術的四核內核的一個內核的100%利用率。 – 2013-05-14 14:33:24

+0

你機器上有多少核心? – LukeHennerley 2013-05-14 14:33:30

+0

@LukeHennerley任務管理器顯示8(它是Intel i7-3770) – Hershizer33 2013-05-14 14:35:04

回答

3

事實上,你的程序沒有任何方面是實際上能並行運行。

需要按順序完成匹配的生成。直到它找到第一個匹配,它才能找到第二個匹配。 Parallel.ForEach充其量將允許您並行處理序列的結果,但它們仍然依次生成。這就是你大部分時間消耗的工作似乎是在那裏,並沒有收益。

最重要的是,你並不是真的是並行處理結果。循環體中運行的大部分代碼都在調用UI線程的內部,這意味着它全部由單個線程運行。

總之,只有一小部分程序實際上是並行運行的,而使用並行化通常會增加一些開銷;這聽起來像你剛剛得到的不僅僅是這些開銷。 錯誤並不真實,除非有一種有效的方法將初始字符串拆分成幾個較小的卡片,而正則表達式可以單獨解析(並行)。

+0

我想我誤解了正則表達式在.Net中的工作原理。雖然第二行已經完成了,但是你說的是MatchCollection startMatches = Regex.Matches(tempRTB.Text,startPattern);它包含了所有的匹配項,在找到ForEach循環中的下一個之前,仍然必須等待每一個被找到? – Hershizer33 2013-05-14 14:38:41

+1

@ Hershizer33是的。它依賴於延遲執行。如果只打算要求前兩場比賽,那麼不會打擾所有20場比賽。當你問第一個問題時,會發現第一個問題。當你在那之後詢問那個,然後去找到下一個,等等,直到沒有更多。 – Servy 2013-05-14 14:40:54

+0

瞭解,謝謝你不知道...所以唯一的選擇是,也許找到更快的正則表達式模式呢? – Hershizer33 2013-05-14 14:55:24

4

在你的代碼的大部分時間都是在實際選擇中的富文本框中的文本,並設置顏色的部分最有可能的花費。

此代碼不可能並行執行,因爲它必須編組到UI線程 - 您通過tempRTB.Invoke執行此操作。

此外,您明確確保突出顯示不是並行執行,而是通過使用lock語句按順序執行。這是不必要的,因爲所有代碼都是在單個UI線程上運行的。


你可以嘗試改善暫停UI的布點你的表現,而你選擇和顏色的RTB文:

tempRTB.SuspendLayout(); 

// your loop 

tempRTB.ResumeLayout(); 
+0

我明白了,我有道理。那麼它是什麼呢?保持400個結果的硬性限制並以20秒生活? – Hershizer33 2013-05-14 14:37:17

+0

@ Hershizer33:您可以嘗試通過在執行着色時禁用UI更新來縮短選擇時間。 – 2013-05-14 14:40:44

+0

我明白了。有沒有辦法產生我想要的RTF而不觸碰RTB?我首先使用RTB的唯一原因是因爲它有那些方便的功能來爲你做這件事......如果我可以做到這一點,而不需要調用並行線程,它會更快嗎? – Hershizer33 2013-05-14 14:43:54