Обработка повторного входа в асинхронных приложениях (C# и Visual Basic)
При включении асинхронного кода в приложении, рекомендуется по возможности и предотвращение reentrancy, которое ссылается на reentering асинхронной операции до его завершения.Если не указать и не обрабатывается возможности для reentrancy, может привести к непредвиденным результатам.
Содержание раздела
Примечание |
---|
В инструкции Проверку и выполнение приложения примера показано, как выполнять код или как приложение Windows Presentation Foundation (WPF) или как приложение Windows Магазина. Запуск образца как приложение WPF, необходимо иметь Visual Studio 2012, Visual Studio Express 2012 для рабочего стола Windows или .NET Framework 4,5, на компьютере. Запуск образца как приложение Магазина Windows необходимо иметь Windows 8, на компьютере.Кроме того, если требуется запустить пример из Visual Studio, следует установить Visual Studio 2012 или Visual Studio Express 2012 для Windows 8 задать. |
Узнавать Reentrancy
В примере в этом разделе, пользователи выбирали кнопку Запуск, чтобы начать асинхронное приложение, загрузит данные веб-сайтов и вычисляют общее количество байтов, загружены.Синхронная версия образца ответитьTfа будет таким же образом вне зависимости от того, сколько раз пользователь выбирает кнопки, поскольку после в первый раз, поток пользовательского интерфейса не будет игнорировать эти события приложения до завершения выполнения.В асинхронном приложения, однако поток пользовательского интерфейса продолжает работу и, возможно, потребуется повторно асинхронной операции до ее завершения.
В следующем примере показан ожидаемый выводимый результат, если пользователь выбрал кнопку Запуск только один раз.Список загруженных веб-сайтов, содержащее размер в байтах для каждого сайта.Общее число байтов отображается в конце.
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
Однако если пользователь выбрал " несколько раз, то обработчик событий вызывается повторно, и процесс загрузки reentered каждый раз.В результате несколько асинхронных операций, выполняемых одновременно, interleaves вывода результата, и общее количество байтов смущает.
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
Можно просмотреть код, который создает этот результат, перемещая в конце этого раздела.Можно поэкспериментировать с кодом с загрузить решение на локальный компьютер и затем выполнение проекта WebsiteDownload или с помощью кода в конце этого раздела, чтобы создать собственный проект дополнительные сведения и инструкции см. в разделе Проверку и выполнение приложения примера.
Обработка Reentrancy
Можно reentrancy дескриптора различными способами в зависимости от того, что требуется задачу приложения.В этом разделе описаны следующие примеры:
-
Отключить кнопку Запуск пока операция выполняется, чтобы пользователь не сможет прервать его.
Отмена и перезапустите операцию
Отменить любые операции, которая все еще выполняется, когда пользователь выберет кнопку Запуск еще раз, а затем позволяет последним запрошенную операцию продолжения.
Операции и очередь выполняется несколько выходных данных
Разрешите все необходимые операции для выполнения асинхронно, но скоординируйте отображение выходных данных таким образом, чтобы результаты каждой операции и отображаются вместе в порядке.
Отключение доступной кнопку
Можно блок кнопку Запуск пока операция выполняется путем отключения кнопку вверху обработчик событий StartButton_Click.После этого можно снова включить кнопку из блока finally, если операция завершения, чтобы пользователи могли запустить приложение.
Следующий код показывает эти изменения, которые отмечены звездочками.Можно добавить изменения кода в конце этого раздела, загрузить завершенное приложение Примеры Async. Reentrancy в классических приложениях .NETПримеры Async. Reentrancy в приложениях Windows Магазина из.Имя проекта 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;
}
}
В результате изменений, кнопка не будет реагировать при AccessTheWebAsync загрузит веб-сайты, поэтому процесс не reentered.
Отмена и перезапустите операцию
Вместо отключить кнопку Запуск, можно хранить кнопку активной, но, если пользователь выбирает эту кнопку еще раз, отменить операцию, которая уже выполняется и позволяет последним началась операция продолжить.
Дополнительные сведения об отмене см. в разделе Настраивать приложение Async.
Чтобы настроить этот сценарий, внесите следующие изменения к основному коду, который приведен в Проверку и выполнение приложения примера.Также можно загрузить завершенное приложение из. Примеры Async. Reentrancy в приложениях Windows МагазинаПримеры Async. Reentrancy в классических приложениях .NETИмя этого проекта CancelAndRestart.
Объявите переменную CancellationTokenSource, cts, в области для всех методов.
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;
В StartButton_Click определите ли операция уже находится в процессе.Если параметр cts имеет значение NULL (Nothing в Visual Basic), то нет операция еще не открыта.Если значение не NULL, то операция, которая уже выполняется отменена.
' *** 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(); }
Свойству cts в другой значение, которое представляет текущий процесс.
' *** 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;
В конце StartButton_Click, текущий процесс завершен, укажите значение cts значение 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;
Следующий код показывает все изменения в StartButton_Click.Добавление отмечены звездочками.
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;
}
В AccessTheWebAsync можно внести следующие изменения.
Добавьте параметр, чтобы принять токен отмены из StartButton_Click.
Используйте метод GetAsync, чтобы загрузить веб-сайты, поскольку функция GetAsync принимает аргумент CancellationToken.
До вызова метода DisplayResults для отображения результатов для каждого загруженного веб-сайта, проверка ct можно проверить, что текущая операция не была отменена.
Следующий код показывает эти изменения, которые отмечены звездочками.
' *** 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);
}
Если вы выберете кнопку Запуск несколько раз, пока это приложение запускается, оно должно быть подобны, следующий результат.
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
Исключить частично списки, комментарий первая строка кода в StartButton_Click, чтобы очистить текстовое поле каждый раз, когда пользователь перезапустить операцию.
Операции и очередь выполняется несколько выходных данных
В этом примере третий наиболее осложненные в том, что приложение запускает другой асинхронной операции каждый раз, когда пользователь выбирает кнопка Запуск, и все операции выполняются до завершения.Все необходимые операции загрузят веб-сайты из списка асинхронно, но результат выполнения операций последовательно.Это значит, что фактическая действие загрузки чередовать, как видно в Узнавать Reentrancy, но отображает список результатов для каждой группы отдельно.
Операции используют глобальное Task, pendingWork, который служит для отображения привратник процесса.
Можно выполнить этот пример, вставьте изменения в код в Построение приложений или в Загрузить приложение можно воспользоваться инструкциями загрузить пример и щелкните проект QueueResults.
Ниже показано результат, если пользователь выбрал кнопку Запуск только один раз.В метке буквы, a, показывает, что результат выполнения в первый раз кнопки Запуск выбран.Порядок числа указывают URL-адреса в списке целевых объектов загрузки.
#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.
Если пользователь выбирает кнопку Запуск три раза, приложение создает выходные данные, похожий на следующие линии.Линии сведения, которые начинаются с трассировкой знаки фунта (#) хода выполнения приложения.
#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.
Начало групп B и C) до того, как команда a закончила, только выходные данные для каждой группы отображается отдельно.Все выходные данные для группы a, во-первых, за которым следует полностью выходными данными для группы B, а затем полностью выходными данными для группы C.Приложение всегда отображаются группы в порядке, для каждой группы, всегда отображаются сведения об отдельных веб-сайтах URL-адреса в том порядке, в котором отображаются в списке URL-адреса.
Однако нельзя предугадать порядок загрузки фактически происходят.После того как были запущены несколько групп, задачи загрузки, они создают все активные.Нельзя высказывать A-1 загрузил перед B-1, поэтому нельзя высказывать A-1 загрузил перед A-2.
Определения глобальных
Пример кода содержит следующие 2 глобальных объявлений, отображается из всех методов.
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, pendingWork, надзирает процесс отображения и предотвращает любую группу из прерывание операции отображения других групп.Переменная символа, group метки выходные данные из различных групп, чтобы убедиться, что результаты отображаются в ожидаемый порядок.
Обработчик событий click
Обработчик события StartButton_Click, этапы буква группы каждый раз, когда пользователь выберет кнопки Запуск.Затем обработчик вызывает метод AccessTheWebAsync для выполнения операции загрузки.
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.";
}
}
Метод AccessTheWebAsync
Этот пример разделяет AccessTheWebAsync в 2 метода.Первый метод, AccessTheWebAsync, запускает все задачи загрузки для группы и устанавливает pendingWork в элемент управления процессом отображения.Метод использует запрос LINQ (LINQ) и ToArray<TSource> для запуска все задачи загрузки одновременно.
после этого метод AccessTheWebAsync вызывает метод FinishOneGroupAsync, чтобы ожидать завершения каждой загрузки и отображения длину.
FinishOneGroupAsync возвращает задачу, присвоена в pendingWork в AccessTheWebAsync.Это значение позволяет перерывов другой операции, прежде чем задача завершена.
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;
}
Метод FinishOneGroupAsync
Циклы данного метода посредством задачи загрузки в группе, требуется каждый из загруженного веб-сайта, в котором отображается длину и добавление длина в сумме.
Первая выписка в FinishOneGroupAsync использует pendingWork, чтобы вставить метод не мешает с операцией, которая уже в процессе или отображения, уже ожидает.Если такая операция выполняется, то при вводе операция должна ожидать его отключить.
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);
}
Можно выполнить этот пример, вставьте изменения в код в Построение приложений или в Загрузить приложение можно воспользоваться инструкциями загрузить образец, а затем щелкните проект QueueResults.
Объекты
Линии сведения, начинающиеся с символа " # " в выходе из собственного как этот образец работает.
Выходные данные показывают следующие шаблоны.
Команда можно запустить пока предыдущая команда отображает выходные данные, но не прерывается отображение выходных данных предыдущей команды.
#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 значение NULL (Nothing в Visual Basic) в начале FinishOneGroupAsync только для группы a, которая запустила первым.Группирование a, пока не завершено выражение ожидать, когда он достигает FinishOneGroupAsync.Поэтому элемент управления не вернул значение AccessTheWebAsync, а первое указанное в pendingWork, не произошло.
Следующие 2 линии всегда отображаются вместе в выходные данные.Код никогда не прерван между начать операцию групп в StartButton_Click и присвоив задачи для группы в pendingWork.
#Starting group B. #Task assigned for group B. Download tasks are active.
После того, как команда вводит StartButton_Click, операция не завершается выражение ожидать, пока операция не будет вставляется объект FinishOneGroupAsync.Поэтому никакая другая операция не может управлять коэффициента усиления во время этого сегмента кода.
Проверку и выполнение приложения примера
Чтобы лучше понять примера приложения можно загрузить его, создайте его самостоятельно или проверка кода в конце этого раздела без реализации приложения.
Примечание |
---|
Запуск образца как классическое приложение Windows Presentation Foundation (WPF), необходимо иметь Visual Studio 2012, Visual Studio Express 2012 для рабочего стола Windows или .NET Framework 4,5, на компьютере. Запуск образца как приложение Магазина Windows необходимо иметь Windows 8, на компьютере.Кроме того, если требуется запустить пример из Visual Studio, следует установить Visual Studio 2012 или Visual Studio Express 2012 для Windows 8 задать.Visual Studio 2010 не может загрузить проекты, которые предназначены для .NET Framework 4,5. |
Загрузить приложение
Загрузите сжатый файл Примеры Async. Reentrancy в классических приложениях .NET из. Примеры Async. Reentrancy в приложениях Windows Магазина
Распакуйте файл, который загружен, затем запустите Visual Studio.
В строке меню выберите Файл, Открыть, Проект/Решение.
Перейдите в папку, которая содержит распакованный пример кода, а затем откройте файл решения (SLN).
В Обозреватель решений откройте контекстное меню для проекта, который необходимо запустить, и выберите пункт Набор в качестве StartUpProject.
Выберите ключи клавиш CTRL+F5 для построения и выполнения проекта.
Построение приложений
Следующие разделы содержат код для построения примера как приложение WPF или как приложение Магазина Windows.
Построение приложения WPF
Запустите Visual Studio 2012.
В строке меню выберите Файл, Создать, Проект.
Откроется диалоговое окно Новый проект.
В области Установленные шаблоны разверните узел Visual Basic или Visual C#, а затем - Окна.
В списке типов проекта выберите Приложение WPF.
Назовите проект WebsiteDownloadWPF, а затем нажмите кнопку ОК.
В обозревателе решений появится новый проект.
Выберите в редакторе кода Visual Studio вкладку MainWindow.xaml.
Если вкладка не отображается, откройте контекстное меню для MainWindow.xaml в Обозреватель решений, а затем выберите Перейти к коду.
В представлении XAML замените автоматически созданный код на следующий код.
<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>
Простое окно, содержащее текстовое поле и кнопку, отображается в представлении Конструктор MainWindow.xaml.
Добавьте ссылку на System.Net.Http.
В Обозревателе решений откройте контекстное меню для MainWindow.xaml.vb или MainWindow.xaml.cs, а затем выберите Код.
В файле MainWindow.xaml.vb или MainWindow.xaml.cs замените код на следующий.
' 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); } } }
Выберите ключи клавиш CTRL+F5, чтобы запустить программу, а затем несколько раз нажмите кнопку Запуск.
Внесите изменения в Отключение доступной кнопку, Отмена и перезапустите операцию или Операции и очередь выполняется несколько выходных данных для обработки reentrancy.
Построение приложения Windows Магазина
Запустите Visual Studio 2012.
В строке меню выберите Файл, Создать, Проект.
Откроется диалоговое окно Новый проект.
В Установлено в категории Шаблоны, разверните Visual Basic или Visual C#, а затем разверните пункт Магазин Windows.
В списке типов проекта выберите Пустое приложение (XAML).
Назовите проект WebsiteDownloadWin, а затем нажмите кнопку ОК.
В обозревателе решений появится новый проект.
В Обозреватель решений откройте контекстное меню для MainPage.xaml, а затем выберите Открыть.
В окне XAML MainPage.xaml замените код следующим кодом.
<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>
Простое окно, содержащее текстовое поле и кнопку Запуск отображается в окне Разработка MainPage.xaml.
В Обозреватель решений откройте контекстное меню для MainPage.xaml.vb или MainPage.xaml.cs, а затем выберите Просмотреть код.
Замените код в MainPage.xaml.vb или MainPage.xaml.cs следующим кодом.
' 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); } } }
Выберите ключи клавиш CTRL+F5, чтобы запустить программу, а затем несколько раз нажмите кнопку Запуск.
Внесите изменения в Отключение доступной кнопку, Отмена и перезапустите операцию или Операции и очередь выполняется несколько выходных данных для обработки reentrancy.
См. также
Задачи
Основные понятия
Асинхронное программирование с использованием ключевых слов Async и Await (C# и Visual Basic)
Другие ресурсы
Асинхронное программирование приложений магазином (Windows)
Учебник. Вызов асинхронных интерфейсов API в C-# или Visual Basic