title: Why is the same code so much slower in my BackGroundWorker thread than in my GUI thread?
body: <p>I am trying to create a c# WinForms application that searches and highlights text in a RichTextBox. I have created two search methods: one that runs in the GUI thread and one that runs in a BackGroundWorker. The logic in both methods is essentially identical. However, the code in the BGW runs considerably slower.</p>
  
  <p>Please see the results below:</p>
  
  <p>0.25MB Text file searching a common keyword: GUI: 2.9s - BGW: 7.0s<br>
  1MB Text file searching a common keyword: GUI:14.1s - BGW:71.4s<br>
  5MB Text file searching a common keyword: GUI:172s - BGW:1545s</p>
  
  <p>It seems strange to me that the relationship between the time taken for the two methods is not liner with respect to search size.</p>
  
  <p>The application will be used for searching files up to 10MB in size so it is important this is fast. I wanted to use a background worker so the user could see progress and continue reading the file while the search is being performed.</p>
  
  <p>Please see the code for the two methods below:</p>
  
  <pre><code>    // background search thread
      private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
      {
          // Get the BackgroundWorker that raised this event.
          BackgroundWorker worker = sender as BackgroundWorker;
  
          RichTextBox rtb = new RichTextBox();
          RichTextBox results = new RichTextBox();
          rtb.Rtf = e.Argument as string;  //recive text to be searched
  
          int hits = 0; // track number of hits
          int pos = 0;  // track position in rtb
          int i = 0;    // trach current line number for progress report
  
          string lowerT = searchTerm.ToLowerInvariant();
          string lowerl = "";
          int n = 0;
          int len = searchTerm.Length;
  
          foreach (string l in rtb.Lines)
          {
              lowerl = l.ToLowerInvariant();
              n = lowerl.IndexOf(lowerT);
              if (n &gt; -1)
              {
                  while (n &gt; -1)   //if found sterm highlight instances
                  {
                      hits++;     //incriment hits
  
                      //hilight term
                      rtb.SelectionStart = pos + n;
                      rtb.SelectionLength = len;
                      rtb.SelectionBackColor = Color.Yellow;
                      rtb.SelectionColor = Color.Black;
  
                      //find next
                      n = lowerl.IndexOf(lowerT, n + len);
                  }
                  searchRes.Add(pos); // add positon of hit to results list
  
                  //add rtb formatted text to results rtb
                  rtb.SelectionStart = pos;
                  rtb.SelectionLength = l.Length;
                  results.SelectedRtf = rtb.SelectedRtf;
                  results.AppendText(Environment.NewLine);
  
              }
              pos += l.Length + 1; //incriment position
  
              //worker.ReportProgress(++i);
          }
          string[] res = {rtb.Rtf,results.Rtf,hits.ToString()};
          e.Result = res;
      }
  
      // old non threaded search method
      public void OldSearch(string sTerm)
      {
          int hits = 0; // track number of hits
          int pos = 0;  // track position in rtb
          int oldPos = richTextBox1.SelectionStart; //save current positin in rtb
          int oldLen = richTextBox1.SelectionLength;
  
          string lowerT = sTerm.ToLowerInvariant();
  
          sTime = 0;
          System.Threading.Timer tmr = new System.Threading.Timer(new TimerCallback(TimerTask), null, 0, 100);
  
          if (sTerm.Length &gt; 0)
          {
              //clear old search
              ReloadFile();
              richTextBox4.Clear();
              searchRes = new List&lt;int&gt;();
  
              //open results pane
              label1.Text = "Searching for \"" + sTerm + "\"...";
              splitContainer1.Panel2Collapsed = false;
  
              frmFind.Focus();
              frmFind.ShowProgress(true);
  
              foreach (string l in richTextBox1.Lines)
              {
                  string lowerl = l.ToLowerInvariant();
                  int n = lowerl.IndexOf(lowerT);
                  if (n &gt; -1)
                  {
                      while (n &gt; -1)   //if found sterm highlight instances
                      {
                          hits++;     //incriment hits
                          //hilight term
                          richTextBox1.SelectionStart = pos + n;
                          richTextBox1.SelectionLength = sTerm.Length;
                          richTextBox1.SelectionBackColor = Color.Yellow;
                          richTextBox1.SelectionColor = Color.Black;
                          //find next
                          n = lowerl.IndexOf(lowerT, n + sTerm.Length);
                      }
                      searchRes.Add(pos);
                      richTextBox1.SelectionStart = pos;
                      richTextBox1.SelectionLength = l.Length;
                      richTextBox4.SelectedRtf = richTextBox1.SelectedRtf;
                      richTextBox4.AppendText(Environment.NewLine);
                  }
                  pos += l.Length + 1; //incriment position
              }
  
              tmr.Dispose();
  
              float time = (float)sTime / 10;
  
              label1.Text = "Search for \"" + sTerm + "\": Found " + hits + " instances in " + time + " seconds.";
              richTextBox4.SelectionStart = 0;
              richTextBox1.SelectionStart = oldPos;
              richTextBox1.SelectionLength = oldLen;
              richTextBox1.Focus();
              frmFind.ShowProgress(false);
          }
      }
  </code></pre>
  
  <p>NOTES:</p>
  
  <ul>
  <li>I know that the RTB class has its own find method but found this to be considerably slower than my own method.  </li>
  <li>I have read a number of threads regarding BGW performance and most seem to site the use of Invoke methods as the cause but I am using none.  </li>
  <li>I understand the use of multiple threads will make it run slower but was not expecting this much difference.  </li>
  <li>The problem is not with <code>ReportProgress</code> i have commented this line out. The reason i'm doing it this way rather than as a percentage is the calculation to work out the percentage made a big difference. It is actually faster this way</li>
  <li>This <a href="http://www.pcreview.co.uk/forums/using-richtextbox-thread-t1402964.html" rel="noreferrer">link</a> provided by another user describes how I am using my RTB in a non GUI thread. It seems to suggest it shouldn't be a problem but will incur more overheads as it will cause the creation of a message queue. I'm not sure if this will be affecting the performance of the code within my foreach loop. Any comments on the matter would be much appreciated.</li>
  </ul>