Názorný postup: Multithreading s komponentou BackgroundWorker (C# a Visual Basic)
Názorný postup vytvoření aplikace s více podprocesy, která vyhledá výskyty slova do textového souboru.Ukazuje:
Definování třídy s metodou, která mohou být volány BackgroundWorker komponent.
Zpracování událostí vyvolaných BackgroundWorker komponent.
Spuštění BackgroundWorker komponenty ke spuštění metody.
Provádění Cancel tlačítko, které se zastaví BackgroundWorker komponent.
Vytvořit uživatelské rozhraní
Otevřete nový Visual Basic nebo C# Windows aplikace project a vytvořte formulář s názvem Form1.
Přidat dvě tlačítka a čtyři textová pole Form1.
Název objekty uvedené v následující tabulce.
Objekt
Property
Nastavení
První tlačítko
Name, Text
Start Start
Druhé tlačítko
Name, Text
Zrušení Storno
První textové pole
Name, Text
Zdrojový soubor, ""
Druhé textové pole
Name, Text
CompareString, ""
Třetí textové pole
Name, Text
WordsCounted "0"
Čtvrté textové pole
Name, Text
LinesCounted "0"
Přidání popisku vedle každého textového pole.Nastavit Text vlastnosti pro každý štítek, jak je uvedeno v následující tabulce.
Objekt
Property
Nastavení
První štítek
Text
Zdrojový soubor
Druhý popisek
Text
Porovnání řetězce
Třetí popisek
Text
Odpovídající slova
Čtvrtý popisek
Text
Počítáno řádky
Vytvořte komponentu BackgroundWorker a k jeho události odběru
Přidat BackgroundWorker komponenta součásti sekce nástrojů do formuláře.Zobrazí se na hlavním součást formuláře.
Nastavit následující vlastnosti pro objekt BackgroundWorker1 v Visual Basic nebo backgroundWorker1 objektu v jazyce C#.
Property
Nastavení
WorkerReportsProgress
True
WorkerSupportsCancellation
True
C# pouze odběru události objektu backgroundWorker1.V horní části Vlastnosti okna, klepněte události ikonu.Poklepejte RunWorkerCompleted událostí vytvořit metodu obslužnou rutinu události.Postup ProgressChanged a DoWork události.
Definovat metodu, která bude spuštěna v odděleném podprocesu
Z projektu nabídce zvolte Přidat třídu přidat třídy do projektu.Zobrazí se dialogové okno Přidat novou položku.
Vyberte třídy z okna šablony a typ Words.vb nebo Words.cs v poli název.
Klikněte na tlačítko Přidat.Words Třídy je zobrazen.
Přidejte následující kód Words třídy:
Public Class Words ' Object to store the current state, for passing to the caller. Public Class CurrentState Public LinesCounted As Integer Public WordsMatched As Integer End Class Public SourceFile As String Public CompareString As String Private WordCount As Integer = 0 Private LinesCounted As Integer = 0 Public Sub CountWords( ByVal worker As System.ComponentModel.BackgroundWorker, ByVal e As System.ComponentModel.DoWorkEventArgs ) ' Initialize the variables. Dim state As New CurrentState Dim line = "" Dim elapsedTime = 20 Dim lastReportDateTime = Now If CompareString Is Nothing OrElse CompareString = System.String.Empty Then Throw New Exception("CompareString not specified.") End If Using myStream As New System.IO.StreamReader(SourceFile) ' Process lines while there are lines remaining in the file. Do While Not myStream.EndOfStream If worker.CancellationPending Then e.Cancel = True Exit Do Else line = myStream.ReadLine WordCount += CountInString(line, CompareString) LinesCounted += 1 ' Raise an event so the form can monitor progress. If Now > lastReportDateTime.AddMilliseconds(elapsedTime) Then state.LinesCounted = LinesCounted state.WordsMatched = WordCount worker.ReportProgress(0, state) lastReportDateTime = Now End If ' Uncomment for testing. 'System.Threading.Thread.Sleep(5) End If Loop ' Report the final count values. state.LinesCounted = LinesCounted state.WordsMatched = WordCount worker.ReportProgress(0, state) End Using End Sub Private Function CountInString( ByVal SourceString As String, ByVal CompareString As String ) As Integer ' This function counts the number of times ' a word is found in a line. If SourceString Is Nothing Then Return 0 End If Dim EscapedCompareString = System.Text.RegularExpressions.Regex.Escape(CompareString) ' To count all occurrences of the string, even within words, remove ' both instances of "\b". Dim regex As New System.Text.RegularExpressions.Regex( "\b" + EscapedCompareString + "\b", System.Text.RegularExpressions.RegexOptions.IgnoreCase) Dim matches As System.Text.RegularExpressions.MatchCollection matches = regex.Matches(SourceString) Return matches.Count End Function End Class
public class Words { // Object to store the current state, for passing to the caller. public class CurrentState { public int LinesCounted; public int WordsMatched; } public string SourceFile; public string CompareString; private int WordCount; private int LinesCounted; public void CountWords( System.ComponentModel.BackgroundWorker worker, System.ComponentModel.DoWorkEventArgs e) { // Initialize the variables. CurrentState state = new CurrentState(); string line = ""; int elapsedTime = 20; DateTime lastReportDateTime = DateTime.Now; if (CompareString == null || CompareString == System.String.Empty) { throw new Exception("CompareString not specified."); } // Open a new stream. using (System.IO.StreamReader myStream = new System.IO.StreamReader(SourceFile)) { // Process lines while there are lines remaining in the file. while (!myStream.EndOfStream) { if (worker.CancellationPending) { e.Cancel = true; break; } else { line = myStream.ReadLine(); WordCount += CountInString(line, CompareString); LinesCounted += 1; // Raise an event so the form can monitor progress. int compare = DateTime.Compare( DateTime.Now, lastReportDateTime.AddMilliseconds(elapsedTime)); if (compare > 0) { state.LinesCounted = LinesCounted; state.WordsMatched = WordCount; worker.ReportProgress(0, state); lastReportDateTime = DateTime.Now; } } // Uncomment for testing. //System.Threading.Thread.Sleep(5); } // Report the final count values. state.LinesCounted = LinesCounted; state.WordsMatched = WordCount; worker.ReportProgress(0, state); } } private int CountInString( string SourceString, string CompareString) { // This function counts the number of times // a word is found in a line. if (SourceString == null) { return 0; } string EscapedCompareString = System.Text.RegularExpressions.Regex.Escape(CompareString); System.Text.RegularExpressions.Regex regex; regex = new System.Text.RegularExpressions.Regex( // To count all occurrences of the string, even within words, remove // both instances of @"\b" from the following line. @"\b" + EscapedCompareString + @"\b", System.Text.RegularExpressions.RegexOptions.IgnoreCase); System.Text.RegularExpressions.MatchCollection matches; matches = regex.Matches(SourceString); return matches.Count; } }
Zpracování události z podprocesu
Přidejte následující obslužné rutiny událostí hlavního formuláře:
Private Sub BackgroundWorker1_RunWorkerCompleted( ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs ) Handles BackgroundWorker1.RunWorkerCompleted ' This event handler is called when the background thread finishes. ' This method runs on the main thread. If e.Error IsNot Nothing Then MessageBox.Show("Error: " & e.Error.Message) ElseIf e.Cancelled Then MessageBox.Show("Word counting canceled.") Else MessageBox.Show("Finished counting words.") End If End Sub Private Sub BackgroundWorker1_ProgressChanged( ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs ) Handles BackgroundWorker1.ProgressChanged ' This method runs on the main thread. Dim state As Words.CurrentState = CType(e.UserState, Words.CurrentState) Me.LinesCounted.Text = state.LinesCounted.ToString Me.WordsCounted.Text = state.WordsMatched.ToString End Sub
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // This event handler is called when the background thread finishes. // This method runs on the main thread. if (e.Error != null) MessageBox.Show("Error: " + e.Error.Message); else if (e.Cancelled) MessageBox.Show("Word counting canceled."); else MessageBox.Show("Finished counting words."); } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // This method runs on the main thread. Words.CurrentState state = (Words.CurrentState)e.UserState; this.LinesCounted.Text = state.LinesCounted.ToString(); this.WordsCounted.Text = state.WordsMatched.ToString(); }
Start a nový podproces, který spustí metodu WordCount volání
Program přidáte následující postupy:
Private Sub BackgroundWorker1_DoWork( ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs ) Handles BackgroundWorker1.DoWork ' This event handler is where the actual work is done. ' This method runs on the background thread. ' Get the BackgroundWorker object that raised this event. Dim worker As System.ComponentModel.BackgroundWorker worker = CType(sender, System.ComponentModel.BackgroundWorker) ' Get the Words object and call the main method. Dim WC As Words = CType(e.Argument, Words) WC.CountWords(worker, e) End Sub Sub StartThread() ' This method runs on the main thread. Me.WordsCounted.Text = "0" ' Initialize the object that the background worker calls. Dim WC As New Words WC.CompareString = Me.CompareString.Text WC.SourceFile = Me.SourceFile.Text ' Start the asynchronous operation. BackgroundWorker1.RunWorkerAsync(WC) End Sub
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // This event handler is where the actual work is done. // This method runs on the background thread. // Get the BackgroundWorker object that raised this event. System.ComponentModel.BackgroundWorker worker; worker = (System.ComponentModel.BackgroundWorker)sender; // Get the Words object and call the main method. Words WC = (Words)e.Argument; WC.CountWords(worker, e); } private void StartThread() { // This method runs on the main thread. this.WordsCounted.Text = "0"; // Initialize the object that the background worker calls. Words WC = new Words(); WC.CompareString = this.CompareString.Text; WC.SourceFile = this.SourceFile.Text; // Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(WC); }
Volání StartThread metoda z Start tlačítko ve formuláři:
Private Sub Start_Click() Handles Start.Click StartThread() End Sub
private void Start_Click(object sender, EventArgs e) { StartThread(); }
Tlačítko Storno, přestane podproces provádění
Volání StopThread z postupu Click obslužnou rutinu události pro Cancel tlačítko.
Private Sub Cancel_Click() Handles Cancel.Click ' Cancel the asynchronous operation. Me.BackgroundWorker1.CancelAsync() End Sub
private void Cancel_Click(object sender, EventArgs e) { // Cancel the asynchronous operation. this.backgroundWorker1.CancelAsync(); }
Testování
Nyní můžete otestovat aplikace a zkontrolovat zda funguje správně.
Testování aplikace
Stisknutím klávesy F5 spustíte aplikaci.
Při zobrazení formuláře zadejte cestu k souboru pro soubor, který chcete testovat v sourceFile pole.Za předpokladu, že testovací soubor s názvem: Test.txt, zadejte například C:\Test.txt.
V druhé textové pole zadejte slovo nebo frázi pro aplikaci do textového souboru.
Klikněte na tlačítko Start.LinesCounted Tlačítko začít okamžitě stovce.Aplikace se zobrazí zpráva "Počítání dokončeno" je posláno.
Testování tlačítka Storno
Stisknutím klávesy F5 spustit aplikaci a zadat soubor název a hledat slovo předchozího postupu.Přesvědčte, zda zvolený soubor dostatečně velký na to, zda že máte čas zrušit postup před dokončením.
Klepněte Start tlačítko spustit aplikaci.
Klikněte na tlačítko Cancel.Aplikace by měla přestat okamžitě počítání.
Další kroky
Tato aplikace obsahuje některé základní chyba zpracování.Rozpoznání prázdné vyhledávací řetězce.Robustnější tohoto programu můžete provést pomocí zpracování další chyby, jako je například překročení maximálního počtu slov nebo řádků, které mohou být započítány.
Viz také
Úkoly
Názorný postup: Vytváření jednoduché komponenty s více podprocesy pomocí jazyka Visual Basic
Jak: přihlásit a odhlásit odběr z události (Příručka programování C#)