Udostępnij za pośrednictwem


Rozpoczynanie wielu zadań i przetwarzanie ich w chwili zakończenia (C# i Visual Basic)

Za pomocą Task.WhenAny, można uruchomić więcej niż jedno zadanie w tym samym czasie i przetwarzać je jeden po drugim, jak oni jesteś zakończone zamiast przetwarzać je w kolejności, w którym są uruchamiane w.

W poniższym przykładzie użyto kwerendy, aby utworzyć zbiór zadań.Każde zadanie pobiera zawartość określonej witryny sieci Web.W każdej iteracji chwilę pętli, oczekiwany wywołanie do WhenAny zwraca zadanie w zbiorem zadań najpierw kończy jego pobierania.To zadanie jest usuwane z kolekcji i przetworzone.Powtarza się w pętli do kolekcji nie zawiera więcej zadań.

[!UWAGA]

Aby uruchomić przykłady, musisz mieć program Visual Studio 2012 r., programu Visual Studio Express 2012 dla pulpitu systemu Windows, lub 4.5.NET Framework zainstalowana na komputerze.

Pobieranie w przykładzie

Można pobrać pełne projektu Windows Presentation Foundation (WPF) z próbki asynchroniczne: dobrze strojenia Twoja aplikacja a następnie wykonaj poniższe kroki.

  1. Zdekompresuj plik, który zostanie pobrany, a następnie uruchom Visual Studio 2012.

  2. Na pasku menu wybierz kolejno opcje Plik, Otwórz i Projekt/rozwiązanie.

  3. W Otwórz projekt okno dialogowe Otwórz folder, który posiada przykładowy kod, który zostanie zdekompresowany, a następnie otwórz plik rozwiązania (.sln) dla AsyncFineTuningCS lub AsyncFineTuningVB.

  4. W Solution Explorer, otwórz menu skrótów dla ProcessTasksAsTheyFinish projektu, a następnie wybierz jako projekt uruchamiania.

  5. Wybierz klawisz F5, aby uruchomić projekt.

    Wybierz klawisze Ctrl + F5, aby uruchomić projekt bez jej debugowaniem.

  6. Aby zweryfikować, że pobrany długości nie zawsze są wyświetlane w tej samej kolejności, należy uruchomić projekt kilka razy.

Jeśli nie chcesz pobrać projektu, można przejrzeć pliki MainWindow.xaml.vb i MainWindow.xaml.cs na końcu tego tematu.

W przykładzie budynku

W tym przykładzie dodaje do kodu, który będzie rozwijany w Anulowanie pozostałych zadań po zakończeniu jednego (C# i Visual Basic) i używa tego samego interfejsu użytkownika.

Zbudować przykładzie samodzielnie, krok po kroku, postępuj zgodnie z instrukcjami w sekcji "Pobieranie Example", ale wybrać CancelAfterOneTask jako Projekt uruchamiania.Dodać zmiany w tym temacie z AccessTheWebAsync metoda w tym projekcie.Zmiany są oznaczone gwiazdkami.

CancelAfterOneTask projektu już zawiera kwerendę, gdy wykonywana, tworzy to zbiór zadań.Każde wywołanie ProcessURLAsync w poniższym kodzie zwróci Task<TResult> gdzie TResult jest liczbą całkowitą.

Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
    From url In urlList Select ProcessURLAsync(url, client, ct)
IEnumerable<Task<int>> downloadTasksQuery =
    from url in urlList select ProcessURL(url, client, ct);

W pliku MainWindow.xaml.vb lub MainWindow.xaml.cs projektu, należy wprowadzić następujące zmiany do AccessTheWebAsync metoda.

  • Kwerenda jest wykonywana przez zastosowanie Enumerable.ToList<TSource> zamiast ToArray<TSource>.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
    
    List<Task<int>> downloadTasks = downloadTasksQuery.ToList();
    
  • Dodać trochę pętli, która wykonuje następujące kroki dla każdego zadania w kolekcji.

    1. Czeka na wywołaniu WhenAny do identyfikowania pierwszego zadania w kolekcji, aby zakończyć jego pobierania.

      Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
      
      Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
      
    2. Usuwa to zadanie z kolekcji.

      downloadTasks.Remove(firstFinishedTask)
      
      downloadTasks.Remove(firstFinishedTask);
      
    3. Czeka na firstFinishedTask, który jest zwracany przez wywołanie do ProcessURLAsync.firstFinishedTask Jest zmienna Task<TResult> gdzie TReturn jest liczbą całkowitą.Zadanie zostało już wykonane, ale czekają go pobrać długość pobrany witryny sieci Web, jak pokazano w następującym przykładzie.

      Dim length = Await firstFinishedTask
      resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)
      
      int length = await firstFinishedTask;
      resultsTextBox.Text += String.Format("\r\nLength of the download:  {0}", length);
      

Aby zweryfikować, że pobrany długości nie zawsze są wyświetlane w tej samej kolejności należy uruchomić kilka razy projektu.

Informacje dotyczące przestrogiPrzestroga

Można użyć WhenAny w pętli, zgodnie z opisem w przykładzie do rozwiązywania problemów, które mogą obejmować kilka zadań.Jednak inne podejścia są bardziej efektywne, jeśli masz dużą liczbę zadania do przetwarzania.Aby uzyskać dodatkowe informacje i przykłady, zobacz Przetwarzania zadań, jak one pełną.

Kompletny przykład

Poniższy kod jest pełny tekst w pliku MainWindow.xaml.vb lub MainWindow.xaml.cs, na przykład.Gwiazdki oznaczyć elementy, które zostały dodane w tym przykładzie.

Należy zauważyć, że należy dodać punkt odniesienia dla System.Net.Http.

Można pobrać projektu z próbki asynchroniczne: dobrze strojenia Twoja aplikacja.

' Add an Imports directive and a reference for System.Net.Http.
Imports System.Net.Http

' Add the following Imports directive for System.Threading.
Imports System.Threading

Class MainWindow

    ' Declare a System.Threading.CancellationTokenSource.
    Dim cts As CancellationTokenSource


    Private Async Sub startButton_Click(sender As Object, e As RoutedEventArgs)

        ' Instantiate the CancellationTokenSource.
        cts = New CancellationTokenSource()

        resultsTextBox.Clear()

        Try
            Await AccessTheWebAsync(cts.Token)
            resultsTextBox.Text &= vbCrLf & "Downloads complete."

        Catch ex As OperationCanceledException
            resultsTextBox.Text &= vbCrLf & "Downloads canceled." & vbCrLf

        Catch ex As Exception
            resultsTextBox.Text &= vbCrLf & "Downloads failed." & vbCrLf
        End Try

        ' Set the CancellationTokenSource to Nothing when the download is complete.
        cts = Nothing
    End Sub


    ' You can still include a Cancel button if you want to.
    Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)

        If cts IsNot Nothing Then
            cts.Cancel()
        End If
    End Sub


    ' Provide a parameter for the CancellationToken.
    ' Change the return type to Task because the method has no return statement.
    Async Function AccessTheWebAsync(ct As CancellationToken) As Task

        Dim client As HttpClient = New HttpClient()

        ' Call SetUpURLList to make a list of web addresses.
        Dim urlList As List(Of String) = SetUpURLList()

        ' ***Create a query that, when executed, returns a collection of tasks.
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
            From url In urlList Select ProcessURLAsync(url, client, ct)

        ' ***Use ToList to execute the query and start the download tasks. 
        Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()

        ' ***Add a loop to process the tasks one at a time until none remain.
        While downloadTasks.Count > 0
            ' ***Identify the first task that completes.
            Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)

            ' ***Remove the selected task from the list so that you don't
            ' process it more than once.
            downloadTasks.Remove(firstFinishedTask)

            ' ***Await the first completed task and display the results.
            Dim length = Await firstFinishedTask
            resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)
        End While

    End Function


    ' Bundle the processing steps for a website into one async method.
    Async Function ProcessURLAsync(url As String, client As HttpClient, ct As CancellationToken) As Task(Of Integer)

        ' GetAsync returns a Task(Of HttpResponseMessage). 
        Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

        ' Retrieve the website contents from the HttpResponseMessage.
        Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()

        Return urlContents.Length
    End Function


    ' Add a method that creates a list of web addresses.
    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            }
        Return urls
    End Function

End Class


' Sample output:

' Length of the download:  226093
' Length of the download:  412588
' Length of the download:  175490
' Length of the download:  204890
' Length of the download:  158855
' Length of the download:  145790
' Length of the download:  44908
' Downloads complete.
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 a using directive and a reference for System.Net.Http.
using System.Net.Http;

// Add the following using directive.
using System.Threading;


namespace ProcessTasksAsTheyFinish
{
    public partial class MainWindow : Window
    {
        // Declare a System.Threading.CancellationTokenSource.
        CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();

            // Instantiate the CancellationTokenSource.
            cts = new CancellationTokenSource();

            try
            {
                await AccessTheWebAsync(cts.Token);
                resultsTextBox.Text += "\r\nDownloads complete.";
            }
            catch (OperationCanceledException)
            {
                resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
            }
            catch (Exception)
            {
                resultsTextBox.Text += "\r\nDownloads failed.\r\n";
            }

            cts = null;
        }


        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
        }


        async Task AccessTheWebAsync(CancellationToken ct)
        {
            HttpClient client = new HttpClient();

            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();

            // ***Create a query that, when executed, returns a collection of tasks.
            IEnumerable<Task<int>> downloadTasksQuery =
                from url in urlList select ProcessURL(url, client, ct);

            // ***Use ToList to execute the query and start the tasks. 
            List<Task<int>> downloadTasks = downloadTasksQuery.ToList();

            // ***Add a loop to process the tasks one at a time until none remain.
            while (downloadTasks.Count > 0)
            {
                    // Identify the first task that completes.
                    Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

                    // ***Remove the selected task from the list so that you don't
                    // process it more than once.
                    downloadTasks.Remove(firstFinishedTask);

                    // Await the completed task.
                    int length = await firstFinishedTask;
                    resultsTextBox.Text += String.Format("\r\nLength of the download:  {0}", length);
            }
        }


        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            };
            return urls;
        }


        async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct)
        {
            // GetAsync returns a Task<HttpResponseMessage>. 
            HttpResponseMessage response = await client.GetAsync(url, ct);

            // Retrieve the website contents from the HttpResponseMessage.
            byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

            return urlContents.Length;
        }
    }
}

// Sample Output:

// Length of the download:  226093
// Length of the download:  412588
// Length of the download:  175490
// Length of the download:  204890
// Length of the download:  158855
// Length of the download:  145790
// Length of the download:  44908
// Downloads complete.

Zobacz też

Informacje

WhenAny

Koncepcje

Dostrajanie aplikacji Async (C# i Visual Basic)

Asynchroniczne programowania przy użyciu asynchronicznej i poczekać (C# i Visual Basic)

Inne zasoby

Próbka asynchroniczne: Dobrze dostrajania aplikacji