我正在嘗試創建一個c#WinForms應用程序,它可以在RichTextBox中搜索並突出顯示文本。我創建了兩種搜索方法:一種在GUI線程中運行,另一種在BackGroundWorker中運行。兩種方法的邏輯基本相同。但是,BGW中的代碼運行速度要慢得多。爲什麼在我的BackGroundWorker線程中相同的代碼比在我的GUI線程中慢得多?
請參閱下面的結果:
0.25 MB文本文件搜索一些常見的關鍵字:GUI:2.9s - BGW:7.0s
1MB文本文件搜索一些常見的關鍵字:GUI:14.1s - BGW:71.4小號
5MB的文本文件中搜索一個共同的關鍵詞:GUI:172S - BGW:1545s
我覺得奇怪,我採取了兩種方法的時間之間的關係,不針對班輪搜索大小。
該應用程序將用於搜索最大10MB的文件,所以重要的是這個速度很快。我想使用後臺工作人員,以便用戶可以看到進度並在搜索執行時繼續閱讀文件。
請參閱代碼下面的兩種方法:
// 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 > -1)
{
while (n > -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 > 0)
{
//clear old search
ReloadFile();
richTextBox4.Clear();
searchRes = new List<int>();
//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 > -1)
{
while (n > -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);
}
}
注:
- 我知道RTB類都有自己的查找方法,但發現這是比我自己的要慢得多方法。
- 我已經閱讀了許多有關BGW性能的主題,並且大多數網站似乎都使用Invoke方法作爲原因,但我沒有使用任何方法。
- 我明白多線程的使用會讓它運行速度變慢,但並沒有期待這麼大的差別。
- 問題不在
ReportProgress
我已經評論了這條線。我這樣做的原因,而不是作爲一個百分比是計算,以確定百分比有很大的不同。它實際上更快這種方式 - 這link由另一位用戶提供描述我如何在非GUI線程中使用我的RTB。它似乎暗示它不應該是一個問題,但會招致更多的開銷,因爲它會導致創建消息隊列。我不確定這是否會影響我的foreach循環中的代碼的性能。對此事的任何意見將不勝感激。
也許後臺線程的優先級設置過低屏幕的可見區域? 「基本相同的代碼」也不是相同的代碼。 – GCaiazzo
@GCaiazzo感謝您的評論。我嘗試設置優先級,如下所示:'System.Diagnostics.Process.GetCurrentProcess()。PriorityClass = System.Diagnostics.ProcessPriorityClass.High;'但它似乎沒有什麼區別。 (我知道這是一個壞主意,因爲線程是彙集的,我只是做了一個測試)。當我說基本相同時,我指的是foreach循環中的邏輯。這是一樣的。我認爲^^ – mfa
我正在看的代碼實際上是一件壞事(tm)。第一個問題是你正在後臺線程上創建一個'Control'('RichTextBox')。作爲一個經驗法則,只需在主UI線程上創建一個控件。當你在後臺線程上創建一個'Control'時,你在背景中做了一堆廢話,不應該在後臺線程上完成。相反,將字符串傳遞給後臺線程,讓後臺線程返回突出顯示的索引,以便前臺線程可以突出顯示後臺線程找到的文本塊。 –