Podpora vícenásobného přístupu v aplikacích s modifikátorem Async (C# a Visual Basic)
Pokud zahrnete asynchronního kódu vaší aplikace, by měly vzít v úvahu a případně zabránit vícenásobnému přístupu, který se vztahuje k nutnosti opětovného zadávání asynchronní operace, dříve, než byl dokončen.Pokud není identifikovat a zpracování možností pro vícenásobný, může vést k neočekávaným výsledkům.
V tomto tématu
[!POZNÁMKA]
Pokyny v Revize a spuštění příkladu App ukazují, jak spustit kód aplikace Windows Presentation Foundation (WPF) nebo jako úložiště systému Windows aplikace.
Chcete-li spustit příklad aplikace WPF, musíte mít Visual Studio 2012, Visual Studio Express 2012 pro program Windows Desktop, nebo 4.5 rozhraní .NET Framework, ve vašem počítači nainstalována.
Chcete-li spustit příklad jako Windows Store aplikace, musíte mít v počítači nainstalována aplikace Windows 8.Kromě toho, pokud má být spuštění příkladu ze sady Visual Studio, je také nutné Visual Studio 2012 nebo Visual Studio Express 2012 pro Windows 8 nainstalován.
UZNÁVAJÍCE vícenásobný
V příkladu v tomto tématu se uživatelé rozhodnout Start tlačítko zahájíte asynchronní app, který stáhne řady webů a vypočítá celkový počet bajtů, které byly staženy.Synchronní verze v příkladu by odpovídal stejný způsobem bez ohledu na to o tom, kolikrát uživatel vybere tlačítko, protože po prvním vlákno uživatelského rozhraní, bude ignorovat tyto události až do ukončení aplikace.V asynchronním app však vlákno uživatelského rozhraní i nadále odpovídat a asynchronní operace může být znovu, dříve, než byl dokončen.
Následující příklad ukazuje Očekávaný výstup, pokud uživatel zvolí Start tlačítko pouze jednou.Zobrazí se seznam stažených webových stránek s velikost v bajtech, jednotlivých webů.Celkový počet bajtů, které se objeví na konci.
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
Ale pokud uživatel na tlačítko více než jednou, obslužná rutina události je volána opakovaně a proces stahování je znovu zadat pokaždé, když.V důsledku toho více asynchronních operací, které jsou spuštěny současně výstup interleaves výsledky a celkový počet bajtů je matoucí.
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
7. msdn.microsoft.com 42972
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
7. msdn.microsoft.com 42972
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
Můžete zkontrolovat kód, který vytváří tento výstup pomocí posuvníku na konci tohoto tématu.Můžete experimentovat s kódem stahování řešení do místního počítače a následným spuštěním projektu WebsiteDownload nebo pomocí kódu na konci tohoto tématu k vytvoření projektu pro další informace a pokyny naleznete v tématu Revize a spuštění příkladu App.
Vícenásobný zpracování
Je možné zpracovat vícenásobný v mnoha různými způsoby v závislosti na tom, co má vaše aplikace provést.Toto téma popisuje následující příklady:
-
Zakázat Start tlačítko operace je spuštěn tak, aby uživatel ji ukončit.
Zrušit a znovu spusťte operaci
Zrušit operaci, která je stále spuštěn, když uživatel vybere Start znovu na tlačítko a umožňují nedávno požadovaná operace pokračovat.
Spuštění více operací a výstup ve frontě
Povolit že všechny požadované operace spustit asynchronně, ale koordinovat zobrazení výstupu tak, aby společně a v pořadí, zobrazí se výsledky ze všech operací.
Zakázat tlačítko Start
Můžete blokovat Start tlačítko zakázáním tlačítko v horní části je spuštěna operace StartButton_Click obslužnou rutinu události.Potom znovu povolte tlačítko uvnitř finally blokovat po ukončení operace, takže uživatelé mohou spouštět aplikace znovu.
Následující kód znázorňuje tyto změny, které jsou označeny hvězdičkami.Změny můžete přidat kód na konci tohoto tématu nebo si můžete stáhnout hotové app z asynchronní vzorky: vícenásobný v .NET Desktop Apps nebo asynchronní vzorky: vícenásobnému přístupu v systému Windows Store Apps.Název projektu je 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
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// 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 (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.";
}
// ***Enable the Start button in case you want to run the program again.
finally
{
StartButton.IsEnabled = true;
}
}
V důsledku změn, nebude tlačítko reagovat, nebude při AccessTheWebAsync stahování webových stránek, tak proces nelze znovu zadat.
Zrušit a znovu spusťte operaci
Namísto zakázání Start tlačítko, můžete zachovat aktivní tlačítko však, pokud uživatel klepne na tlačítko znovu, zrušit operaci, která je již spuštěna a pokračovat v operaci naposledy spuštěno.
Další informace o zrušení, viz Jemné vyladění asynchronní aplikace.
Chcete-li nastavit tento scénář, proveďte následující změny základní kód, který je k dispozici v Revize a spuštění příkladu App.Také můžete stáhnout hotové app z asynchronní vzorky: vícenásobný v .NET Desktop Apps nebo asynchronní vzorky: vícenásobnému přístupu v systému Windows Store Apps.Název tohoto projektu je CancelAndRestart.
Deklarovat CancellationTokenSource proměnné, cts, který je v oboru pro všechny metody.
Class MainWindow // Or Class MainPage ' *** Declare a System.Threading.CancellationTokenSource. Dim cts As CancellationTokenSource
public partial class MainWindow : Window // Or class MainPage { // *** Declare a System.Threading.CancellationTokenSource. CancellationTokenSource cts;
V StartButton_Click, zjistit, zda operace již probíhá.Pokud hodnota cts má hodnotu null (Nothing v jazyce Visual Basic), žádná operace je již aktivní.Pokud hodnota není null, je zrušena operace, která je již spuštěna.
' *** If a download process is already underway, cancel it. If cts IsNot Nothing Then cts.Cancel() End If
// *** If a download process is already underway, cancel it. if (cts != null) { cts.Cancel(); }
Set cts na jinou hodnotu, která představuje aktuální proces.
' *** Now set cts to cancel the current process if the button is chosen again. Dim newCTS As CancellationTokenSource = New CancellationTokenSource() cts = newCTS
// *** Now set cts to a new value that you can use to cancel the current process // if the button is chosen again. CancellationTokenSource newCTS = new CancellationTokenSource(); cts = newCTS;
Na konci StartButton_Click, aktuální proces je dokončen, tak nastavte hodnotu cts zpět na hodnotu null.
' *** When the process completes, signal that another process can proceed. If cts Is newCTS Then cts = Nothing End If
// *** When the process is complete, signal that another process can begin. if (cts == newCTS) cts = null;
Následující kód ukazuje všechny změny v StartButton_Click.Budou přidány jsou označeny hvězdičkami.
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
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// This line is commented out to make the results clearer in the output.
//ResultsTextBox.Clear();
// *** If a download process is already underway, cancel it.
if (cts != null)
{
cts.Cancel();
}
// *** Now set cts to cancel the current process if the button is chosen again.
CancellationTokenSource newCTS = new CancellationTokenSource();
cts = newCTS;
try
{
// ***Send cts.Token to carry the message if there is a cancellation request.
await AccessTheWebAsync(cts.Token);
}
// *** Catch cancellations separately.
catch (OperationCanceledException)
{
ResultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
// *** When the process is complete, signal that another process can proceed.
if (cts == newCTS)
cts = null;
}
V AccessTheWebAsync, proveďte následující změny.
Přidejte parametr přijmout token zrušení z StartButton_Click.
Použití GetAsync metoda stahování webových stránek, protože GetAsync přijímá CancellationToken argument.
Před voláním DisplayResults Chcete-li zobrazit výsledky pro každý web stažené, ct Chcete-li ověřit, že aktuální operaci nebyl zrušen.
Následující kód znázorňuje tyto změny, které jsou označeny hvězdičkami.
' *** 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
// *** Provide a parameter for the CancellationToken from StartButton_Click.
async Task AccessTheWebAsync(CancellationToken ct)
{
// Declare an HttpClient object.
HttpClient client = new HttpClient();
// Make a list of web addresses.
List<string> urlList = SetUpURLList();
var total = 0;
var position = 0;
foreach (var url in urlList)
{
// *** Use the HttpClient.GetAsync method because it accepts a
// cancellation token.
HttpResponseMessage response = await client.GetAsync(url, ct);
// *** Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
// *** Check for cancellations before displaying information about the
// latest site.
ct.ThrowIfCancellationRequested();
DisplayResults(url, urlContents, ++position);
// Update the total.
total += urlContents.Length;
}
// Display the total count for all of the websites.
ResultsTextBox.Text +=
string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total);
}
Pokud se rozhodnete Start tlačítko několikrát během spuštění této aplikace je má vracet výsledky, které se podobají následující výstup.
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 122505
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
Download canceled.
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
Download canceled.
1. msdn.microsoft.com/en-us/library/hh191443.aspx 83732
2. msdn.microsoft.com/en-us/library/aa578028.aspx 205273
3. msdn.microsoft.com/en-us/library/jj155761.aspx 29019
4. msdn.microsoft.com/en-us/library/hh290140.aspx 117152
5. msdn.microsoft.com/en-us/library/hh524395.aspx 68959
6. msdn.microsoft.com/en-us/library/ms404677.aspx 197325
7. msdn.microsoft.com 42972
8. msdn.microsoft.com/en-us/library/ff730837.aspx 146159
TOTAL bytes returned: 890591
Odstranit dílčí seznamy, Odkomentujte prvního řádku kódu v StartButton_Click Chcete-li vymazat textové pole pokaždé, když uživatel restartuje operace.
Spuštění více operací a výstup ve frontě
Tento třetí příklad je nejvíce komplikované, v tom, že aplikace spustí pokaždé, když uživatel zvolí jiná asynchronní operace Start tlačítka a všechny operace spustit až do ukončení.Stáhnout všechny požadované operace weby ze seznamu asynchronně, ale výstup z operací se zobrazí postupně.To znamená prokládaný skutečné stahování aktivity jako výstup v UZNÁVAJÍCE vícenásobný pořady, ale seznam výsledků pro každou skupinu je předkládán samostatně.
Operace sdílet globální Task, pendingWork, která slouží jako server gatekeeper pro zpracování zobrazení.
V tomto příkladu můžete spustit vložením změny do kódu v Vytvoření aplikace, nebo můžete postupovat podle pokynů v Stahování aplikace ke stažení vzorku a spuštění projektu QueueResults.
Následující výstup ukazuje výsledek, pokud uživatel zvolí Start tlačítko pouze jednou.Popisek písmeno A označuje, že výsledek je z první Start stisknuté tlačítko.Čísla zobrazit pořadí adres URL v seznamu cílů ke stažení.
#Starting group A.
#Task assigned for group A.
A-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/en-us/library/aa578028.aspx 209858
A-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260
A-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186
A-7. msdn.microsoft.com 53266
A-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148020
TOTAL bytes returned: 918876
#Group A is complete.
Jestliže uživatel zvolí Start tlačítko třikrát, aplikace vytvoří výstup, který se podobá následující řádky.Informace řádky, které začínají libry znak (#) sledování průběhu aplikace.
#Starting group A.
#Task assigned for group A.
A-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389
A-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089
A-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
A-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
A-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71259
A-6. msdn.microsoft.com/en-us/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/en-us/library/ff730837.aspx 148010
TOTAL bytes returned: 916095
B-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389
B-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089
B-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
B-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
B-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260
B-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186
#Group A is complete.
B-7. msdn.microsoft.com 53266
B-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010
TOTAL bytes returned: 916097
C-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389
C-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089
#Group B is complete.
C-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870
C-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027
C-5. msdn.microsoft.com/en-us/library/hh524395.aspx 72765
C-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186
C-7. msdn.microsoft.com 56190
C-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010
TOTAL bytes returned: 920526
#Group C is complete.
Skupiny B a C spustit dříve, než byla dokončena A skupiny, ale zobrazí výstup pro každou skupinu zvlášť.Veškerý výstup pro skupiny A zobrazí první, následované veškerý výstup pro skupinu B a potom všechny výstup pro skupinu C.Aplikace vždy zobrazí v pořadí skupiny a pro každou skupinu vždy zobrazí informace o jednotlivých webů v pořadí, ve kterém adresy URL se zobrazí v seznamu adres URL.
Však nelze předvídat, pořadí, ve kterém soubory ke stažení skutečně dojde.Po spuštění více skupin jsou všechny aktivní úkoly ke stažení, které generují.Nelze předpokládat, že A-1 před B 1, budou staženy a nelze předpokládat, že A-1 budou staženy před A 2.
Definice globálních
Ukázkový kód obsahuje následující dvě globální deklarace, které jsou viditelné ze všech metod.
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)
public partial class MainWindow : Window // Class MainPage in Windows Store app.
{
// ***Declare the following variables where all methods can access them.
private Task pendingWork = null;
private char group = (char)('A' - 1);
Task Proměnné, pendingWork, zadaný řídí karty zobrazí proces a zabrání jakékoli skupiny došlo k přerušení operace zobrazení jinou skupinu.Proměnné znak group, označí výstup z různých skupin, chcete-li ověřit, že výsledky se zobrazí v očekávaném pořadí.
Obslužné rutiny pro událost kliknutí
Obslužná rutina události StartButton_Click, zvýší písmeno skupiny pokaždé, když uživatel zvolí Start tlačítko.Potom volání rutiny AccessTheWebAsync Chcete-li spustit stahování operace.
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
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
// ***Verify that each group's results are displayed together, and that
// the groups display in order, by marking each group with a letter.
group = (char)(group + 1);
ResultsTextBox.Text += string.Format("\r\n\r\n#Starting group {0}.", group);
try
{
// *** Pass the group value to AccessTheWebAsync.
char finishedGroup = await AccessTheWebAsync(group);
// The following line verifies a successful return from the download and
// display procedures.
ResultsTextBox.Text += string.Format("\r\n\r\n#Group {0} is complete.\r\n", finishedGroup);
}
catch (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.";
}
}
Metoda AccessTheWebAsync
V tomto příkladu rozdělí AccessTheWebAsync do dvou metod.První metoda, AccessTheWebAsync, spustí všechny úkoly ke stažení pro skupinu a nastavuje pendingWork pro řízení zobrazení procesu.Metoda používá dotaz integrovaný do jazyka (LINQ dotaz) a ToArray<TSource> spustit všechny úlohy stahování současně.
AccessTheWebAsyncpotom zavolá FinishOneGroupAsync kde čekají na dokončení jednotlivých souborů ke stažení a zobrazení její délku.
FinishOneGroupAsyncVrátí úkol, který je přiřazen k pendingWork v AccessTheWebAsync.Že hodnota zabraňuje přerušení jinou operací před dokončením úkolu.
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
private async Task<char> AccessTheWebAsync(char grp)
{
HttpClient client = new HttpClient();
// Make a list of the web addresses to download.
List<string> urlList = SetUpURLList();
// ***Kick off the downloads. The application of ToArray activates all the download tasks.
Task<byte[]>[] getContentTasks = urlList.Select(url => client.GetByteArrayAsync(url)).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("\r\n#Task assigned for group {0}. Download tasks are active.\r\n", 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;
}
Metoda FinishOneGroupAsync
Tato metoda se cyklicky prochází úlohy stahování ve skupině čekají na každý z nich, zobrazení délky stažené webu a přidání do celkové délky.
První příkaz v FinishOneGroupAsync používá pendingWork abyste se ujistili, že metoda zadávání není v konfliktu s operací, která je již v procesu zobrazení nebo který již čeká.Pokud probíhá takové operace, operace zadávání čekat jeho zapnutí.
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
private async Task FinishOneGroupAsync(List<string> urls, Task<byte[]>[] contentTasks, char grp)
{
// ***Wait for the previous group to finish displaying results.
if (pendingWork != null) await pendingWork;
int total = 0;
// contentTasks is the array of Tasks that was created in AccessTheWebAsync.
for (int i = 0; i < contentTasks.Length; i++)
{
// Await the download of a particular URL, and then display the URL and
// its length.
byte[] content = await contentTasks[i];
DisplayResults(urls[i], content, i, grp);
total += content.Length;
}
// Display the total count for all of the websites.
ResultsTextBox.Text +=
string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total);
}
V tomto příkladu můžete spustit vložením změny do kódu v Vytvoření aplikace, nebo můžete postupovat podle pokynů v Stahování aplikace ke stažení vzorku a spuštění projektu QueueResults.
Body zájmu
Informace řádky, které začínají znak křížku (#) ve výstupu vysvětlit, jak funguje v tomto příkladu.
Výstup zobrazuje následující vzory.
Skupiny lze spustit, zatímco předchozí skupiny zobrazuje výstup, ale nedošlo k přerušení zobrazení výstupu předchozí skupiny.
#Starting group A. #Task assigned for group A. Download tasks are active. A-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87389 A-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089 A-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870 A-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119037 A-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260 #Starting group B. #Task assigned for group B. Download tasks are active. A-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186 A-7. msdn.microsoft.com 53078 A-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010 TOTAL bytes returned: 915919 B-1. msdn.microsoft.com/en-us/library/hh191443.aspx 87388 B-2. msdn.microsoft.com/en-us/library/aa578028.aspx 207089 B-3. msdn.microsoft.com/en-us/library/jj155761.aspx 30870 #Group A is complete. B-4. msdn.microsoft.com/en-us/library/hh290140.aspx 119027 B-5. msdn.microsoft.com/en-us/library/hh524395.aspx 71260 B-6. msdn.microsoft.com/en-us/library/ms404677.aspx 199186 B-7. msdn.microsoft.com 53078 B-8. msdn.microsoft.com/en-us/library/ff730837.aspx 148010 TOTAL bytes returned: 915908
pendingWork Úkol má hodnotu null (Nothing v jazyce Visual Basic) na začátku FinishOneGroupAsync pouze pro skupiny A, což zahájení první.Skupiny A dosud nedokončil výraz await, když dosáhne FinishOneGroupAsync.Proto ovládací prvek nebyl vrácen AccessTheWebAsynca první přiřazení k pendingWork nedošlo.
Následující dva řádky vždy zobrazeny společně ve výstupu.Kód je nikdy přerušena mezi spuštěním operace do skupiny StartButton_Click a přiřazení úkolu pro skupinu pendingWork.
#Starting group B. #Task assigned for group B. Download tasks are active.
Po vstupu do skupiny StartButton_Click, operace nebude dokončena výraz await do operace v FinishOneGroupAsync.Žádná operace tedy může získat kontrolu během tohoto segmentu kódu.
Revize a spuštění příkladu App
Pro lepší pochopení příkladu aplikace, můžete ji stáhnout, sestavit sami nebo zkontrolovat kód na konci tohoto tématu bez implementace aplikace.
[!POZNÁMKA]
Chcete-li spustit příklad jako pracovní plochy aplikace Windows Presentation Foundation (WPF), musíte mít Visual Studio 2012, Visual Studio Express 2012 pro program Windows Desktop, nebo 4.5 rozhraní .NET Framework, ve vašem počítači nainstalována.
Chcete-li spustit příklad jako Windows Store aplikace, musíte mít v počítači nainstalována aplikace Windows 8.Kromě toho, pokud má být spuštění příkladu ze sady Visual Studio, je také nutné Visual Studio 2012 nebo Visual Studio Express 2012 pro Windows 8 nainstalován.Visual Studio 2010 nelze načíst projekty, které jsou určeny pro rozhraní .NET Framework 4.5.
Stahování aplikace
Stažení komprimovaného souboru z asynchronní vzorky: vícenásobný v .NET Desktop Apps nebo asynchronní vzorky: vícenásobnému přístupu v systému Windows Store Apps.
Dekomprimujte soubor, který jste stáhli a potom spusťte aplikaci Visual Studio.
Na panelu nabídky vyberte možnosti Soubor, Otevřít, Projekt/řešení.
Přejděte do složky obsahující dekomprimovaný ukázkový kód a potom otevřete soubor řešení (.sln).
V Průzkumníku, otevřete místní nabídku pro projekt, který chcete spustit a potom zvolte nastavit jako StartUpProject.
Zvolte klávesy CTRL + F5, sestavte a spusťte projekt.
Vytvoření aplikace
Následující části obsahují kód k vytvoření příkladu jako aplikace WPF nebo Windows Store aplikace.
K vytvoření aplikace WPF
Spusťte aplikaci Visual Studio 2012.
V panelu nabídek zvolte Soubor, Nový, Projekt.
Otevře se dialogové okno Nový projekt.
V Nainstalované šablony podokně rozbalte jazyka Visual Basic nebo **Visual C#**a potom rozbalte uzel Windows.
V seznamu typy projektů, vyberte Aplikace WPF.
Název projektu WebsiteDownloadWPFa pak zvolte OK tlačítko.
V podokně Řešení - průzkumník se zobrazí nový projekt.
V editoru Visual Studio kód, zvolte MainWindow.xaml kartu.
Pokud na kartě není zobrazen, otevřete místní nabídku pro MainWindow.xaml v Průzkumníkua pak zvolte Zobrazit kód.
V XAML zobrazení MainWindow.xaml, nahraďte kód následujícím kódem.
<Window x:Class="MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWPF" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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>
<Window x:Class="WebsiteDownloadWPF.MainWindow" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWPF" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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>
Jednoduché okno, které obsahuje textové pole a tlačítko se zobrazí v Návrh zobrazení MainWindow.xaml.
Přidejte referenci na System.Net.Http.
V Průzkumníku, otevřete místní nabídku pro MainWindow.xaml.vb nebo MainWindow.xaml.cs a pak zvolte Zobrazit kód.
V MainWindow.xaml.vb nebo MainWindow.xaml.cs kód nahraďte následující kód.
' 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) ' 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/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/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("http://", "") ' 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 Class
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; // Add the following using directives, and add a reference for System.Net.Http. using System.Net.Http; using System.Threading; namespace WebsiteDownloadWPF { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void StartButton_Click(object sender, RoutedEventArgs e) { // This line is commented out to make the results clearer in the output. //ResultsTextBox.Text = ""; try { await AccessTheWebAsync(); } catch (Exception) { ResultsTextBox.Text += "\r\nDownloads failed."; } } private async Task AccessTheWebAsync() { // Declare an HttpClient object. HttpClient client = new HttpClient(); // Make a list of web addresses. List<string> urlList = SetUpURLList(); var total = 0; var position = 0; foreach (var url in urlList) { // GetByteArrayAsync returns a task. At completion, the task // produces a byte array. byte[] urlContents = await client.GetByteArrayAsync(url); DisplayResults(url, urlContents, ++position); // Update the total. total += urlContents.Length; } // Display the total count for all of the websites. ResultsTextBox.Text += string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total); } private List<string> SetUpURLList() { List<string> urls = new List<string> { "https://msdn.microsoft.com/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/library/ff730837.aspx" }; return urls; } private void DisplayResults(string url, byte[] content, int pos) { // 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://". var displayURL = url.Replace("http://", ""); // Display position in the URL list, the URL, and the number of bytes. ResultsTextBox.Text += string.Format("\n{0}. {1,-58} {2,8}", pos, displayURL, content.Length); } } }
Klávesy CTRL + F5 spusťte program a pak zvolte Vybrat Start tlačítko několikrát.
Proveďte požadované změny z Zakázat tlačítko Start, Zrušit a znovu spusťte operaci, nebo Spuštění více operací a výstup ve frontě ke zpracování vícenásobnému přístupu.
Chcete-li sestavit app úložiště systému Windows
Spusťte aplikaci Visual Studio 2012.
V panelu nabídek zvolte Soubor, Nový, Projekt.
Otevře se dialogové okno Nový projekt.
V nainstalovat, šablony kategorie, rozbalte jazyka Visual Basic nebo **Visual C#**a potom rozbalte položku Úložiště systému Windows.
V seznamu typy projektů, vyberte Prázdné App XAML ().
Název projektu WebsiteDownloadWina pak zvolte OK tlačítko.
V podokně Řešení - průzkumník se zobrazí nový projekt.
V Průzkumníku, otevřete místní nabídku pro MainPage.xaml a pak zvolte otevřete.
V XAML okno MainPage.xaml, nahraďte kód následujícím kódem.
<Page x:Class="WebsiteDownloadWin.MainPage" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:WebsiteDownloadWin" xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" FontSize="12"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="325,77,0,0" VerticalAlignment="Top" Click="StartButton_Click" Height="145" Background="#FFA89B9B" FontSize="36" Width="711" /> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" Margin="325,222,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="546" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" Width="711" FontFamily="Lucida Console" /> </Grid> </Page>
Jednoduché okno, které obsahuje textové pole a Start tlačítko se zobrazí v Návrh okno MainPage.xaml.
V Průzkumníku, MainPage.xaml.vb nebo MainPage.xaml.cs otevřete místní nabídku a pak zvolte Zobrazit kód.
Nahraďte kód ve MainPage.xaml.vb nebo MainPage.xaml.cs následující kód.
' Add the following Imports statements. Imports System.Threading.Tasks Imports System.Threading Imports System.Net.Http Public NotInheritable Class MainPage Inherits Page Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) End Sub 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 = "" 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/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/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("http://", "") ' 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 Class
using System; using System.Collections.Generic; using System.IO; using System.Linq; using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; // Add the following using directives. using System.Threading.Tasks; using System.Threading; using System.Net.Http; namespace WebsiteDownloadWin { public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); } private async void StartButton_Click(object sender, RoutedEventArgs e) { // This line is commented out to make the results clearer in the output. //ResultsTextBox.Text = ""; try { await AccessTheWebAsync(); } catch (Exception) { ResultsTextBox.Text += "\r\nDownloads failed."; } } private async Task AccessTheWebAsync() { // Declare an HttpClient object. HttpClient client = new HttpClient(); // Make a list of web addresses. List<string> urlList = SetUpURLList(); var total = 0; var position = 0; foreach (var url in urlList) { // GetByteArrayAsync returns a task. At completion, the task // produces a byte array. byte[] urlContents = await client.GetByteArrayAsync(url); DisplayResults(url, urlContents, ++position); // Update the total. total += urlContents.Length; } // Display the total count for all of the websites. ResultsTextBox.Text += string.Format("\r\n\r\nTOTAL bytes returned: {0}\r\n", total); } private List<string> SetUpURLList() { List<string> urls = new List<string> { "https://msdn.microsoft.com/en-us/library/hh191443.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/jj155761.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/hh524395.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/library/ff730837.aspx" }; return urls; } private void DisplayResults(string url, byte[] content, int pos) { // 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://". var displayURL = url.Replace("http://", ""); // Display position in the URL list, the URL, and the number of bytes. ResultsTextBox.Text += string.Format("\n{0}. {1,-58} {2,8}", pos, displayURL, content.Length); } } }
Klávesy CTRL + F5 spusťte program a pak zvolte Vybrat Start tlačítko několikrát.
Proveďte požadované změny z Zakázat tlačítko Start, Zrušit a znovu spusťte operaci, nebo Spuštění více operací a výstup ve frontě ke zpracování vícenásobnému přístupu.
Viz také
Úkoly
Názorný postup: Přístup K webu pomocí asynchronní a vyčkání (C# a Visual Basic)
Koncepty
Asynchronní asynchronní pro programování a očekávat (C# a Visual Basic)
Další zdroje
Asynchronní programování (apps úložiště systému Windows)
Quickstart: volání asynchronní rozhraní API v jazyce C# nebo Visual Basic