Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Wenn Sie asynchronen Code in der App einschließen, sollten Sie erneutes Eintreten, also den erneuten Beginn eines asynchronen Vorgangs vor seinem Abschließen, berücksichtigen und möglicherweise verhindern. Wenn Sie Möglichkeiten für erneutes Eintreten nicht identifizieren und behandeln, kann dies zu unerwarteten Ergebnissen führen.
Hinweis
Zum Ausführen des Beispiels müssen Sie Visual Studio 2012 oder höher und .NET Framework 4.5 oder höher auf Ihrem Computer installiert haben.
Hinweis
Transport Layer Security (TLS) Version 1.2 ist jetzt die Mindestversion für die App-Entwicklung. Wenn Ihre App auf eine .NET Framework-Version vor 4.7 ausgerichtet ist, lesen Sie den folgenden Artikel für bewährte Methoden für Transport Layer Security (TLS) mit .NET Framework.
Erkennen von Ablaufinvarianz
Im Beispiel in diesem Thema wählen Benutzer eine Schaltfläche " Start " aus, um eine asynchrone App zu initiieren, die eine Reihe von Websites herunterlädt, und berechnet die Gesamtanzahl der heruntergeladenen Bytes. Eine synchrone Version des Beispiels reagiert auf die gleiche Weise, unabhängig davon, wie oft ein Benutzer die Schaltfläche auswäht, da der UI-Thread nach dem ersten Mal diese Ereignisse ignoriert, bis die App ausgeführt wird. In einer asynchronen App reagiert der UI-Thread jedoch weiterhin, und Sie können den asynchronen Vorgang erneut ausführen, bevor er abgeschlossen wurde.
Das folgende Beispiel zeigt die erwartete Ausgabe, wenn der Benutzer die Schaltfläche "Start " nur einmal auswäht. Eine Liste der heruntergeladenen Websites wird mit der Größe jeder Website in Byte angezeigt. Die Gesamtanzahl der Bytes wird am Ende angezeigt.
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
5. msdn.microsoft.com/library/hh524395.aspx 68959
6. msdn.microsoft.com/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
Wenn der Benutzer die Schaltfläche jedoch mehrmals auswähelt, wird der Ereignishandler wiederholt aufgerufen, und der Downloadvorgang wird jedes Mal erneut aufgerufen. Daher werden mehrere asynchrone Vorgänge gleichzeitig ausgeführt, die Ausgabe interleasiert die Ergebnisse, und die Gesamtanzahl der Bytes ist verwirrend.
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
5. msdn.microsoft.com/library/hh524395.aspx 68959
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
6. msdn.microsoft.com/library/ms404677.aspx 197325
3. msdn.microsoft.com/library/jj155761.aspx 29019
7. msdn.microsoft.com 42972
4. msdn.microsoft.com/library/hh290140.aspx 117152
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
5. msdn.microsoft.com/library/hh524395.aspx 68959
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
6. msdn.microsoft.com/library/ms404677.aspx 197325
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
7. msdn.microsoft.com 42972
5. msdn.microsoft.com/library/hh524395.aspx 68959
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
6. msdn.microsoft.com/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
Sie können den Code überprüfen, der diese Ausgabe erzeugt, indem Sie zum Ende dieses Themas scrollen. Sie können mit dem Code experimentieren, indem Sie die Lösung auf Ihren lokalen Computer herunterladen und dann das WebsiteDownload-Projekt ausführen oder den Code am Ende dieses Themas verwenden, um Ihr eigenes Projekt zu erstellen. Weitere Informationen und Anweisungen finden Sie unter "Überprüfen und Ausführen der Beispiel-App".
Umgang mit Ablaufinvarianz
Sie können den Wiedereintritt auf unterschiedliche Weise behandeln, abhängig davon, was Ihre App tun soll. In diesem Thema werden die folgenden Beispiele vorgestellt:
Schaltfläche "Start" deaktivieren
Deaktivieren Sie die Startschaltfläche , während der Vorgang ausgeführt wird, damit der Benutzer ihn nicht unterbrechen kann.
Abbrechen und Neustarten des Vorgangs
Brechen Sie alle Vorgänge ab, die noch ausgeführt werden, wenn der Benutzer die Schaltfläche "Start " erneut auswählt, und lassen Sie den zuletzt angeforderten Vorgang dann fortsetzen.
Mehrere Vorgänge ausführen und die Ausgabe in eine Warteschlange stellen
Zulassen, dass alle angeforderten Vorgänge asynchron ausgeführt werden, aber die Anzeige der Ausgabe koordinieren, sodass die Ergebnisse aus den einzelnen Vorgängen zusammen und in der Reihenfolge angezeigt werden.
Schaltfläche "Start" deaktivieren
Sie können die Startschaltfläche blockieren, während ein Vorgang ausgeführt wird, indem Sie die Schaltfläche am oberen Rand des StartButton_Click Ereignishandlers deaktivieren. Sie können die Schaltfläche dann von innerhalb eines Finally Blocks wieder aktivieren, wenn der Vorgang abgeschlossen ist, damit Benutzer die App erneut ausführen können.
Der folgende Code zeigt diese Änderungen, die mit Sternchen gekennzeichnet sind. Sie können die Änderungen am Ende dieses Themas dem Code hinzufügen oder die fertige App aus Async Samples herunterladen: Reentrancy in .NET Desktop Apps. Der Projektname ist DisableStartButton.
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' This line is commented out to make the results clearer in the output.
'ResultsTextBox.Text = ""
' ***Disable the Start button until the downloads are complete.
StartButton.IsEnabled = False
Try
Await AccessTheWebAsync()
Catch ex As Exception
ResultsTextBox.Text &= vbCrLf & "Downloads failed."
' ***Enable the Start button in case you want to run the program again.
Finally
StartButton.IsEnabled = True
End Try
End Sub
Aufgrund der Änderungen reagiert die Schaltfläche nicht, während AccessTheWebAsync die Websites heruntergeladen werden, sodass der Vorgang nicht erneut ausgeführt werden kann.
Abbrechen und Neustarten des Vorgangs
Anstatt die Schaltfläche "Start " zu deaktivieren, können Sie die Schaltfläche aktiv halten, aber wenn der Benutzer diese Schaltfläche erneut auswählt, brechen Sie den bereits ausgeführten Vorgang ab, und lassen Sie den zuletzt gestarteten Vorgang fortsetzen.
Weitere Informationen zum Abbruch finden Sie unterFine-Tuning Ihre Asynchrone Anwendung (Visual Basic).For more information about cancellation, seeFine-Tuning Your Async Application (Visual Basic).
Um dieses Szenario einzurichten, nehmen Sie die folgenden Änderungen am grundlegenden Code vor, der in der Überprüfung und Ausführung der Beispiel-App bereitgestellt wird. Sie können die fertige App auch aus Async Samples herunterladen: Reentrancy in .NET Desktop Apps. Der Name dieses Projekts lautet CancelAndRestart.
Deklarieren Sie eine CancellationTokenSource Variable,
ctsdie sich für alle Methoden im Gültigkeitsbereich befindet.Class MainWindow // Or Class MainPage ' *** Declare a System.Threading.CancellationTokenSource. Dim cts As CancellationTokenSourceErmitteln Sie in
StartButton_Click, ob bereits ein Vorgang ausgeführt wird. Wenn der WertctsistNothing, ist kein Vorgang bereits aktiv. Wenn der Wert nichtNothingist, wird der bereits ausgeführte Vorgang abgebrochen.' *** If a download process is already underway, cancel it. If cts IsNot Nothing Then cts.Cancel() End IfLegen Sie diesen
ctsWert auf einen anderen Wert fest, der den aktuellen Prozess darstellt.' *** Now set cts to cancel the current process if the button is chosen again. Dim newCTS As CancellationTokenSource = New CancellationTokenSource() cts = newCTSAm Ende des
StartButton_Clickist der aktuelle Prozess abgeschlossen. Setzen Sie daher den Wert vonctszurück aufNothing.' *** When the process completes, signal that another process can proceed. If cts Is newCTS Then cts = Nothing End If
Der folgende Code zeigt alle Änderungen in StartButton_Click. Die Ergänzungen sind mit Sternchen gekennzeichnet.
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' This line is commented out to make the results clearer.
'ResultsTextBox.Text = ""
' *** If a download process is underway, cancel it.
If cts IsNot Nothing Then
cts.Cancel()
End If
' *** Now set cts to cancel the current process if the button is chosen again.
Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
cts = newCTS
Try
' *** Send a token to carry the message if the operation is canceled.
Await AccessTheWebAsync(cts.Token)
Catch ex As OperationCanceledException
ResultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf
Catch ex As Exception
ResultsTextBox.Text &= vbCrLf & "Downloads failed."
End Try
' *** When the process is complete, signal that another process can proceed.
If cts Is newCTS Then
cts = Nothing
End If
End Sub
Nehmen Sie in AccessTheWebAsync die folgenden Änderungen vor.
Fügen Sie einen Parameter hinzu, um das Storniertoken von
StartButton_Clickzu akzeptieren.Verwenden Sie die GetAsync Methode, um die Websites herunterzuladen, weil
GetAsyncein CancellationToken Argument akzeptiert.Bevor Sie
DisplayResultsaufrufen, um die Ergebnisse für jede heruntergeladene Website anzuzeigen, aktivieren Siect, um sicherzustellen, dass der aktuelle Vorgang nicht abgebrochen wurde.
Der folgende Code zeigt diese Änderungen, die mit Sternchen gekennzeichnet sind.
' *** Provide a parameter for the CancellationToken from StartButton_Click.
Private Async Function AccessTheWebAsync(ct As CancellationToken) As Task
' Declare an HttpClient object.
Dim client = New HttpClient()
' Make a list of web addresses.
Dim urlList As List(Of String) = SetUpURLList()
Dim total = 0
Dim position = 0
For Each url In urlList
' *** Use the HttpClient.GetAsync method because it accepts a
' cancellation token.
Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)
' *** Retrieve the website contents from the HttpResponseMessage.
Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
' *** Check for cancellations before displaying information about the
' latest site.
ct.ThrowIfCancellationRequested()
position += 1
DisplayResults(url, urlContents, position)
' Update the total.
total += urlContents.Length
Next
' Display the total count for all of the websites.
ResultsTextBox.Text &=
String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned: " & total & vbCrLf)
End Function
Wenn Sie während der Ausführung dieser App mehrmals die Schaltfläche "Start " auswählen, sollte sie Ergebnisse erzeugen, die der folgenden Ausgabe ähneln:
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 122505
5. msdn.microsoft.com/library/hh524395.aspx 68959
6. msdn.microsoft.com/library/ms404677.aspx 197325
Download canceled.
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
Download canceled.
1. msdn.microsoft.com/library/hh191443.aspx 83732
2. msdn.microsoft.com/library/aa578028.aspx 205273
3. msdn.microsoft.com/library/jj155761.aspx 29019
4. msdn.microsoft.com/library/hh290140.aspx 117152
5. msdn.microsoft.com/library/hh524395.aspx 68959
6. msdn.microsoft.com/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
Zum Ausschließen der Teillisten entfernen Sie die Kommentarmarkierungen der ersten Codezeile in StartButton_Click, um das Textfeld bei jedem erneuten Start des Vorgangs zu löschen.
Ausführen mehrerer Vorgänge und Einreihen der Ausgabe in die Warteschlange
Dieses dritte Beispiel ist das komplexeste, da die App jedes Mal, wenn der Benutzer die Startschaltfläche auswählt, einen weiteren asynchronen Vorgang startet und alle Vorgänge bis zum Abschluss ausgeführt werden. Alle angeforderten Vorgänge laden Websites asynchron aus der Liste herunter, die Ausgabe der Vorgänge wird jedoch sequenziell dargestellt. Das bedeutet, die tatsächliche Downloadaktivität überlappt, wie es die Ausgabe in Erkennen von Ablaufinvarianz zeigt, die Ergebnislisten für jede Gruppe aber getrennt angezeigt werden.
Die Vorgänge geben global Task, pendingWork frei, der als Gatekeeper für den Anzeigenprozess dient.
Sie können dieses Beispiel ausführen, indem Sie die Änderungen in den Code in das Erstellen der App einfügen, oder Sie können den Anweisungen zum Herunterladen der App folgen, um das Beispiel herunterzuladen und dann das QueueResults-Projekt auszuführen.
Die folgende Ausgabe zeigt das Ergebnis an, wenn der Benutzer die Schaltfläche "Start " nur einmal auswäht. Das Buchstabenetikett A gibt an, dass das Ergebnis beim ersten Auswählen der Schaltfläche "Start " stammt. Die Zahlen zeigen die Reihenfolge der URLs in der Liste der Downloadziele an.
#Starting group A.
#Task assigned for group A.
A-1. msdn.microsoft.com/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/library/aa578028.aspx 209858
A-3. msdn.microsoft.com/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/library/hh524395.aspx 71260
A-6. msdn.microsoft.com/library/ms404677.aspx 199186
A-7. msdn.microsoft.com 53266
A-8. msdn.microsoft.com/library/ff730837.aspx 148020
TOTAL bytes returned: 918876
#Group A is complete.
Wenn der Benutzer dreimal die Startschaltfläche auswäht, erzeugt die App Ausgaben, die den folgenden Zeilen ähneln. Die Informationszeilen, die mit einem Rautezeichen (#) beginnen, verfolgen den Fortschritt der Anwendung.
#Starting group A.
#Task assigned for group A.
A-1. msdn.microsoft.com/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/library/aa578028.aspx 207089
A-3. msdn.microsoft.com/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/library/hh524395.aspx 71259
A-6. msdn.microsoft.com/library/ms404677.aspx 199185
#Starting group B.
#Task assigned for group B.
A-7. msdn.microsoft.com 53266
#Starting group C.
#Task assigned for group C.
A-8. msdn.microsoft.com/library/ff730837.aspx 148010
TOTAL bytes returned: 916095
B-1. msdn.microsoft.com/library/hh191443.aspx 87389
B-2. msdn.microsoft.com/library/aa578028.aspx 207089
B-3. msdn.microsoft.com/library/jj155761.aspx 30870
B-4. msdn.microsoft.com/library/hh290140.aspx 119027
B-5. msdn.microsoft.com/library/hh524395.aspx 71260
B-6. msdn.microsoft.com/library/ms404677.aspx 199186
#Group A is complete.
B-7. msdn.microsoft.com 53266
B-8. msdn.microsoft.com/library/ff730837.aspx 148010
TOTAL bytes returned: 916097
C-1. msdn.microsoft.com/library/hh191443.aspx 87389
C-2. msdn.microsoft.com/library/aa578028.aspx 207089
#Group B is complete.
C-3. msdn.microsoft.com/library/jj155761.aspx 30870
C-4. msdn.microsoft.com/library/hh290140.aspx 119027
C-5. msdn.microsoft.com/library/hh524395.aspx 72765
C-6. msdn.microsoft.com/library/ms404677.aspx 199186
C-7. msdn.microsoft.com 56190
C-8. msdn.microsoft.com/library/ff730837.aspx 148010
TOTAL bytes returned: 920526
#Group C is complete.
Gruppen B und C beginnen, bevor Gruppe A abgeschlossen ist, die Ausgabe für jede Gruppe wird jedoch separat angezeigt. Alle Ausgaben für Gruppe A werden zuerst angezeigt, gefolgt von der gesamten Ausgabe für Gruppe B und dann alle Ausgaben für Gruppe C. Die App zeigt die Gruppen immer in der reihenfolge an und zeigt für jede Gruppe immer die Informationen zu den einzelnen Websites in der Reihenfolge an, in der die URLs in der Liste der URLs angezeigt werden.
Sie können jedoch nicht vorhersagen, in welcher Reihenfolge die Downloads tatsächlich auftreten. Nachdem mehrere Gruppen gestartet wurden, sind die von ihnen generierten Downloadaufgaben alle aktiv. Sie können nicht davon ausgehen, dass A-1 vor B-1 heruntergeladen wird, und Sie können nicht davon ausgehen, dass A-1 vor A-2 heruntergeladen wird.
Globale Definitionen
Der Beispielcode enthält die folgenden beiden globalen Deklarationen, die von allen Methoden sichtbar sind.
Class MainWindow ' Class MainPage in Windows Store app.
' ***Declare the following variables where all methods can access them.
Private pendingWork As Task = Nothing
Private group As Char = ChrW(AscW("A") - 1)
Die Task Variable pendingWorküberwacht den Anzeigevorgang und verhindert, dass eine Gruppe den Anzeigevorgang einer anderen Gruppe unterbricht. Die Zeichenvariable group, bezeichnet die Ausgabe aus verschiedenen Gruppen, um zu überprüfen, ob die Ergebnisse in der erwarteten Reihenfolge angezeigt werden.
Der Click-Ereignishandler
Mit dem Ereignishandler StartButton_Click wird der Gruppenbuchstabe bei jedem Auswählen der Schaltfläche Start erhöht. Dann ruft der Handler AccessTheWebAsync auf, um den Downloadvorgang auszuführen.
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' ***Verify that each group's results are displayed together, and that
' the groups display in order, by marking each group with a letter.
group = ChrW(AscW(group) + 1)
ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Starting group {0}.", group)
Try
' *** Pass the group value to AccessTheWebAsync.
Dim finishedGroup As Char = Await AccessTheWebAsync(group)
' The following line verifies a successful return from the download and
' display procedures.
ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Group {0} is complete." & vbCrLf, finishedGroup)
Catch ex As Exception
ResultsTextBox.Text &= vbCrLf & "Downloads failed."
End Try
End Sub
Die AccessTheWebAsync-Methode
In diesem Beispiel wird AccessTheWebAsync in zwei Methoden aufgeteilt. Die erste Methode AccessTheWebAsync startet alle Downloadaufgaben für eine Gruppe und richtet pendingWork ein, um den Anzeigevorgang zu steuern. Die Methode verwendet eine LINQ-Abfrage (Language Integrated Query) und ToArray startet alle Downloadaufgaben gleichzeitig.
AccessTheWebAsync ruft dann FinishOneGroupAsync auf, um den Abschluss jedes Downloads abzuwarten und dessen Länge anzuzeigen.
FinishOneGroupAsync gibt eine Aufgabe zurück, die pendingWork in AccessTheWebAsync zugewiesen ist. Dieser Wert verhindert Unterbrechungen durch einen anderen Vorgang, bevor die Aufgabe abgeschlossen ist.
Private Async Function AccessTheWebAsync(grp As Char) As Task(Of Char)
Dim client = New HttpClient()
' Make a list of the web addresses to download.
Dim urlList As List(Of String) = SetUpURLList()
' ***Kick off the downloads. The application of ToArray activates all the download tasks.
Dim getContentTasks As Task(Of Byte())() =
urlList.Select(Function(addr) client.GetByteArrayAsync(addr)).ToArray()
' ***Call the method that awaits the downloads and displays the results.
' Assign the Task that FinishOneGroupAsync returns to the gatekeeper task, pendingWork.
pendingWork = FinishOneGroupAsync(urlList, getContentTasks, grp)
ResultsTextBox.Text &=
String.Format(vbCrLf & "#Task assigned for group {0}. Download tasks are active." & vbCrLf, grp)
' ***This task is complete when a group has finished downloading and displaying.
Await pendingWork
' You can do other work here or just return.
Return grp
End Function
Die FinishOneGroupAsync-Methode
Diese Methode durchgibt die Downloadaufgaben in einer Gruppe, wartet auf jeden einzelnen, zeigt die Länge der heruntergeladenen Website an und fügt die Länge zum Gesamtwert hinzu.
Die erste Anweisung in FinishOneGroupAsync verwendet pendingWork, um sicherzustellen, dass das Betreten der Methode nicht in einen Vorgang eingreift, der sich bereits im Anzeigeprozess befindet oder bereits wartet. Wenn ein solcher Vorgang ausgeführt wird, wird der eintretende Vorgang solange aufgeschoben, bis er an der Reihe ist.
Private Async Function FinishOneGroupAsync(urls As List(Of String), contentTasks As Task(Of Byte())(), grp As Char) As Task
' Wait for the previous group to finish displaying results.
If pendingWork IsNot Nothing Then
Await pendingWork
End If
Dim total = 0
' contentTasks is the array of Tasks that was created in AccessTheWebAsync.
For i As Integer = 0 To contentTasks.Length - 1
' Await the download of a particular URL, and then display the URL and
' its length.
Dim content As Byte() = Await contentTasks(i)
DisplayResults(urls(i), content, i, grp)
total += content.Length
Next
' Display the total count for all of the websites.
ResultsTextBox.Text &=
String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned: " & total & vbCrLf)
End Function
Sie können dieses Beispiel ausführen, indem Sie die Änderungen in den Code in das Erstellen der App einfügen, oder Sie können den Anweisungen zum Herunterladen der App folgen, um das Beispiel herunterzuladen, und dann das QueueResults-Projekt ausführen.
Interessante Punkte
Die Informationszeilen, die mit einem Nummernzeichen (#) in der Ausgabe beginnen, erläutern die Funktionsweise dieses Beispiels.
Die Ausgabe zeigt die folgenden Muster.
Eine Gruppe kann gestartet werden, während eine vorherige Gruppe ihre Ausgabe anzeigt, aber die Anzeige der Ausgabe der vorherigen Gruppe wird nicht unterbrochen.
#Starting group A. #Task assigned for group A. Download tasks are active. A-1. msdn.microsoft.com/library/hh191443.aspx 87389 A-2. msdn.microsoft.com/library/aa578028.aspx 207089 A-3. msdn.microsoft.com/library/jj155761.aspx 30870 A-4. msdn.microsoft.com/library/hh290140.aspx 119037 A-5. msdn.microsoft.com/library/hh524395.aspx 71260 #Starting group B. #Task assigned for group B. Download tasks are active. A-6. msdn.microsoft.com/library/ms404677.aspx 199186 A-7. msdn.microsoft.com 53078 A-8. msdn.microsoft.com/library/ff730837.aspx 148010 TOTAL bytes returned: 915919 B-1. msdn.microsoft.com/library/hh191443.aspx 87388 B-2. msdn.microsoft.com/library/aa578028.aspx 207089 B-3. msdn.microsoft.com/library/jj155761.aspx 30870 #Group A is complete. B-4. msdn.microsoft.com/library/hh290140.aspx 119027 B-5. msdn.microsoft.com/library/hh524395.aspx 71260 B-6. msdn.microsoft.com/library/ms404677.aspx 199186 B-7. msdn.microsoft.com 53078 B-8. msdn.microsoft.com/library/ff730837.aspx 148010 TOTAL bytes returned: 915908Der
pendingWork-Task ist zu Beginn vonNothingnur für Gruppe AFinishOneGroupAsync, die zuerst gestartet wurde. Gruppe A hat bei Erreichen vonFinishOneGroupAsynceinen Erwartungsausdruck noch nicht abgeschlossen. Daher wurde die Kontrolle nicht anAccessTheWebAsynczurückgegeben, und die erste Zuordnung zupendingWorkist noch nicht erfolgt.Die folgenden beiden Zeilen werden immer in der Ausgabe zusammen angezeigt. Der Code wird nie unterbrochen zwischen dem Starten eines Vorgangs einer Gruppe in
StartButton_Clickund der Zuweisung einer Aufgabe an die Gruppe inpendingWork.#Starting group B. #Task assigned for group B. Download tasks are active.Nachdem eine Gruppe in
StartButton_Clickeintritt, schließt der Vorgang einen Erwartungsausdruck erst ab, wenn der Vorgang inFinishOneGroupAsynceintritt. Daher kann kein anderer Vorgang während dieses Codesegments die Kontrolle erlangen.
Überprüfen und Ausführen der Beispiel-App
Um die Beispiel-App besser zu verstehen, können Sie sie herunterladen, selbst erstellen oder den Code am Ende dieses Themas überprüfen, ohne die App zu implementieren.
Hinweis
Um das Beispiel als Windows Presentation Foundation (WPF)-Desktop-App auszuführen, müssen Sie Visual Studio 2012 oder höher und .NET Framework 4.5 oder höher auf Ihrem Computer installiert haben.
Herunterladen der App
Laden Sie die komprimierte Datei aus Async Samples herunter: Reentrancy in .NET Desktop Apps.
Dekomprimieren Sie die heruntergeladene Datei, und starten Sie Dann Visual Studio.
Wählen Sie auf der Menüleiste "Datei", "Öffnen", "Projekt/Projektmappe" aus.
Navigieren Sie zu dem Ordner, der den dekomprimierten Beispielcode enthält, und öffnen Sie dann die Lösungsdatei (.sln).
Öffnen Sie im Lösungs-Explorer das Kontextmenü für das Projekt, das Sie ausführen möchten, und wählen Sie dann "Als Startprojekt festlegen" aus.
Wählen Sie die STRG+F5-Tasten aus, um das Projekt zu erstellen und auszuführen.
Erstellen der App
Der folgende Abschnitt enthält den Code zum Erstellen des Beispiels als WPF-App.
So erstellen Sie eine WPF-App
Starten Sie Visual Studio.
Klicken Sie in der Menüleiste auf Datei, Neu, Projekt.
Das Dialogfeld "Neues Projekt " wird geöffnet.
Erweitern Sie im Bereich "Installierte Vorlagen " Visual Basic, und erweitern Sie dann Windows.
Wählen Sie in der Liste der Projekttypen WPF-Anwendung aus.
Benennen Sie das Projekt
WebsiteDownloadWPF, wählen Sie .NET Framework-Version von 4.6 oder höher aus, und klicken Sie dann auf die Schaltfläche "OK ".Das neue Projekt wird im Projektmappen-Explorer angezeigt.
Wählen Sie im Visual Studio Code-Editor die Registerkarte "MainWindow.xaml " aus.
Wenn die Registerkarte nicht sichtbar ist, öffnen Sie das Kontextmenü für "MainWindow.xaml" im Projektmappen-Explorer, und wählen Sie dann "Code anzeigen" aus.
Ersetzen Sie in der XAML-Ansicht von "MainWindow.xaml" den Code durch den folgenden Code.
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWPF" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Width="517" Height="360"> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="-1,0,0,0" VerticalAlignment="Top" Click="StartButton_Click" Height="53" Background="#FFA89B9B" FontSize="36" Width="518" /> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" Margin="-1,53,0,-36" TextWrapping="Wrap" VerticalAlignment="Top" Height="343" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" Width="518" FontFamily="Lucida Console" /> </Grid> </Window>Ein einfaches Fenster mit einem Textfeld und einer Schaltfläche wird in der Entwurfsansicht von "MainWindow.xaml" angezeigt.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Verweise und wählen Sie "Verweis hinzufügen" aus.
Fügen Sie einen Verweis für System.Net.Http, wenn er noch nicht ausgewählt ist.
Öffnen Sie im Lösungs-Explorer das Kontextmenü für MainWindow.xaml.vb, und wählen Sie dann Code anzeigen aus.
Ersetzen Sie in MainWindow.xaml.vb den Code durch den folgenden Code.
' Add the following Imports statements, and add a reference for System.Net.Http. Imports System.Net.Http Imports System.Threading Class MainWindow Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol Or System.Net.SecurityProtocolType.Tls12 ' This line is commented out to make the results clearer in the output. 'ResultsTextBox.Text = "" Try Await AccessTheWebAsync() Catch ex As Exception ResultsTextBox.Text &= vbCrLf & "Downloads failed." End Try End Sub Private Async Function AccessTheWebAsync() As Task ' Declare an HttpClient object. Dim client = New HttpClient() ' Make a list of web addresses. Dim urlList As List(Of String) = SetUpURLList() Dim total = 0 Dim position = 0 For Each url In urlList ' GetByteArrayAsync returns a task. At completion, the task ' produces a byte array. Dim urlContents As Byte() = Await client.GetByteArrayAsync(url) position += 1 DisplayResults(url, urlContents, position) ' Update the total. total += urlContents.Length Next ' Display the total count for all of the websites. ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned: " & total & vbCrLf) End Function Private Function SetUpURLList() As List(Of String) Dim urls = New List(Of String) From { "https://msdn.microsoft.com/library/hh191443.aspx", "https://msdn.microsoft.com/library/aa578028.aspx", "https://msdn.microsoft.com/library/jj155761.aspx", "https://msdn.microsoft.com/library/hh290140.aspx", "https://msdn.microsoft.com/library/hh524395.aspx", "https://msdn.microsoft.com/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/library/ff730837.aspx" } Return urls End Function Private Sub DisplayResults(url As String, content As Byte(), pos As Integer) ' Display the length of each website. The string format is designed ' to be used with a monospaced font, such as Lucida Console or ' Global Monospace. ' Strip off the "http:'". Dim displayURL = url.Replace("https://", "") ' Display position in the URL list, the URL, and the number of bytes. ResultsTextBox.Text &= String.Format(vbCrLf & "{0}. {1,-58} {2,8}", pos, displayURL, content.Length) End Sub End ClassWählen Sie die STRG+F5-Tasten aus, um das Programm auszuführen, und wählen Sie dann mehrmals die Schaltfläche "Start " aus.
Nehmen Sie die Änderungen aus Die Schaltfläche „Start“ deaktivieren, Den Vorgang abbrechen und neu starten oder Mehrere Vorgänge ausführen und die Ausgabe in eine Warteschlange stellen vor, um mit Ablaufinvarianz umzugehen.