Поделиться через


Обработка повторного входа в асинхронных приложениях (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 дескриптора различными способами в зависимости от того, что требуется задачу приложения.В этом разделе описаны следующие примеры:

JJ651641.collapse_all(ru-ru,VS.110).gifОтключение доступной кнопку

Можно блок кнопку Запуск пока операция выполняется путем отключения кнопку вверху обработчик событий 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.

JJ651641.collapse_all(ru-ru,VS.110).gifОтмена и перезапустите операцию

Вместо отключить кнопку Запуск, можно хранить кнопку активной, но, если пользователь выбирает эту кнопку еще раз, отменить операцию, которая уже выполняется и позволяет последним началась операция продолжить.

Дополнительные сведения об отмене см. в разделе Настраивать приложение Async.

Чтобы настроить этот сценарий, внесите следующие изменения к основному коду, который приведен в Проверку и выполнение приложения примера.Также можно загрузить завершенное приложение из. Примеры Async. Reentrancy в приложениях Windows МагазинаПримеры Async. Reentrancy в классических приложениях .NETИмя этого проекта CancelAndRestart.

  1. Объявите переменную 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;
    
  2. В 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();
    }
    
  3. Свойству 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;
    
  4. В конце 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, чтобы очистить текстовое поле каждый раз, когда пользователь перезапустить операцию.

JJ651641.collapse_all(ru-ru,VS.110).gifОперации и очередь выполняется несколько выходных данных

В этом примере третий наиболее осложненные в том, что приложение запускает другой асинхронной операции каждый раз, когда пользователь выбирает кнопка Запуск, и все операции выполняются до завершения.Все необходимые операции загрузят веб-сайты из списка асинхронно, но результат выполнения операций последовательно.Это значит, что фактическая действие загрузки чередовать, как видно в Узнавать 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.

JJ651641.collapse_all(ru-ru,VS.110).gifОпределения глобальных

Пример кода содержит следующие 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 метки выходные данные из различных групп, чтобы убедиться, что результаты отображаются в ожидаемый порядок.

JJ651641.collapse_all(ru-ru,VS.110).gifОбработчик событий 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.";
    }
}

JJ651641.collapse_all(ru-ru,VS.110).gifМетод 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;
}

JJ651641.collapse_all(ru-ru,VS.110).gifМетод 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.

JJ651641.collapse_all(ru-ru,VS.110).gifОбъекты

Линии сведения, начинающиеся с символа " # " в выходе из собственного как этот образец работает.

Выходные данные показывают следующие шаблоны.

  • Команда можно запустить пока предыдущая команда отображает выходные данные, но не прерывается отображение выходных данных предыдущей команды.

    #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.

JJ651641.collapse_all(ru-ru,VS.110).gifЗагрузить приложение

  1. Загрузите сжатый файл Примеры Async. Reentrancy в классических приложениях .NET из. Примеры Async. Reentrancy в приложениях Windows Магазина

  2. Распакуйте файл, который загружен, затем запустите Visual Studio.

  3. В строке меню выберите Файл, Открыть, Проект/Решение.

  4. Перейдите в папку, которая содержит распакованный пример кода, а затем откройте файл решения (SLN).

  5. В Обозреватель решений откройте контекстное меню для проекта, который необходимо запустить, и выберите пункт Набор в качестве StartUpProject.

  6. Выберите ключи клавиш CTRL+F5 для построения и выполнения проекта.

JJ651641.collapse_all(ru-ru,VS.110).gifПостроение приложений

Следующие разделы содержат код для построения примера как приложение WPF или как приложение Магазина Windows.

Построение приложения WPF

  1. Запустите Visual Studio 2012.

  2. В строке меню выберите Файл, Создать, Проект.

    Откроется диалоговое окно Новый проект.

  3. В области Установленные шаблоны разверните узел Visual Basic или Visual C#, а затем - Окна.

  4. В списке типов проекта выберите Приложение WPF.

  5. Назовите проект WebsiteDownloadWPF, а затем нажмите кнопку ОК.

    В обозревателе решений появится новый проект.

  6. Выберите в редакторе кода Visual Studio вкладку MainWindow.xaml.

    Если вкладка не отображается, откройте контекстное меню для MainWindow.xaml в Обозреватель решений, а затем выберите Перейти к коду.

  7. В представлении 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.

  8. Добавьте ссылку на System.Net.Http.

  9. В Обозревателе решений откройте контекстное меню для MainWindow.xaml.vb или MainWindow.xaml.cs, а затем выберите Код.

  10. В файле 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);
            }
        }
    }
    
  11. Выберите ключи клавиш CTRL+F5, чтобы запустить программу, а затем несколько раз нажмите кнопку Запуск.

  12. Внесите изменения в Отключение доступной кнопку, Отмена и перезапустите операцию или Операции и очередь выполняется несколько выходных данных для обработки reentrancy.

Построение приложения Windows Магазина

  1. Запустите Visual Studio 2012.

  2. В строке меню выберите Файл, Создать, Проект.

    Откроется диалоговое окно Новый проект.

  3. В Установлено в категории Шаблоны, разверните Visual Basic или Visual C#, а затем разверните пункт Магазин Windows.

  4. В списке типов проекта выберите Пустое приложение (XAML).

  5. Назовите проект WebsiteDownloadWin, а затем нажмите кнопку ОК.

    В обозревателе решений появится новый проект.

  6. В Обозреватель решений откройте контекстное меню для MainPage.xaml, а затем выберите Открыть.

  7. В окне 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.

  8. В Обозреватель решений откройте контекстное меню для MainPage.xaml.vb или MainPage.xaml.cs, а затем выберите Просмотреть код.

  9. Замените код в 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);
            }
        }
    }
    
  10. Выберите ключи клавиш CTRL+F5, чтобы запустить программу, а затем несколько раз нажмите кнопку Запуск.

  11. Внесите изменения в Отключение доступной кнопку, Отмена и перезапустите операцию или Операции и очередь выполняется несколько выходных данных для обработки reentrancy.

См. также

Задачи

Пошаговое руководство. Получение доступа к Интернету с помощью модификатора Async и оператора Await (C# и Visual Basic)

Основные понятия

Асинхронное программирование с использованием ключевых слов Async и Await (C# и Visual Basic)

Другие ресурсы

Асинхронное программирование приложений магазином (Windows)

Учебник. Вызов асинхронных интерфейсов API в C-# или Visual Basic