Udostępnij za pośrednictwem


Anulowanie pozostałych zadań po zakończeniu jednego (C# i Visual Basic)

Za pomocą Task.WhenAny metoda wraz z CancellationToken, można anulować wszystkie pozostałe zadania po wykonaniu jednego zadania.WhenAny Metoda pobiera argument, który jest zbiorem zadań.Metoda uruchamia wszystkie zadania i zwraca jedno zadanie.Pojedynczy zadanie zostało wykonane, po zakończeniu każdego zadania w kolekcji.

W tym przykładzie przedstawiono sposób użycia token odwołania w połączeniu z WhenAny do posiadania na pierwsze zadanie, aby zakończyć ze zbiorem zadań i aby anulować pozostałych zadań.Każde zadanie pliki do pobrania zawartości witryny.W przykładzie wyświetla długość zawartości do zakończenia pierwszego pobierania i anuluje inne pliki do pobrania.

[!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 CancelAfterOneTask 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 różne pliki do pobrania zakończyć po raz pierwszy, należy uruchomić program 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 przykładzie w tym temacie dodawany do projektu, opracowanym w Anulowanie zadania lub listy zadań (C# i Visual Basic) Aby anulować listy zadań.W przykładzie użyto tego samego interfejsu użytkownika, mimo że anulowanie nie jest jawnie użyć przycisku.

Zbudować przykładzie samodzielnie, krok po kroku, postępuj zgodnie z instrukcjami w sekcji "Pobieranie Example", ale wybrać CancelAListOfTasks jako Projekt uruchamiania.Dodaj odpowiednie zmiany w tym temacie do tego projektu.

W pliku MainWindow.xaml.vb lub MainWindow.xaml.cs CancelAListOfTasks projektu, uruchomienie przejścia przez przeniesienie kroków przetwarzania dla każdej witryny sieci Web z pętli w AccessTheWebAsync według następującej metody komunikacji asynchronicznej.

' ***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
// ***Bundle the processing steps for a website into one async method.
async Task<int> ProcessURLAsync(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;
}

W AccessTheWebAsync, w tym przykładzie użyto kwerendy, ToArray<TSource> metodę, a WhenAny do tworzenia i uruchamiania szereg zadań.Stosowanie WhenAny do macierzy zwraca jedno zadanie, gdy oczekiwana, daje w wyniku pierwszego zadania do wykonania zadań w tablicy.

Należy wprowadzić następujące zmiany w AccessTheWebAsync.Gwiazdki oznaczają zmiany w pliku kodu.

  1. Kodu ani usuwać pętli.

  2. Utworzyć kwerendę, który podczas wykonywania produkuje zbiorem zadań rodzajowy.Każde wywołanie ProcessURLAsync zwraca Task<TResult> gdzie TResult jest liczbą całkowitą.

    ' ***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)
    
    // ***Create a query that, when executed, returns a collection of tasks.
    IEnumerable<Task<int>> downloadTasksQuery =
        from url in urlList select ProcessURLAsync(url, client, ct);
    
  3. Call ToArray do wykonywania kwerendy i uruchamianie zadań.Stosowanie WhenAny metoda w następnym kroku będzie wykonanie kwerendy i uruchamianie zadań bez korzystania z ToArray, ale innych metod może nie działać.Najbezpieczniejszym rozwiązaniem jest jawnie wymusić wykonanie kwerendy.

    ' ***Use ToArray to execute the query and start the download tasks. 
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
    // ***Use ToArray to execute the query and start the download tasks. 
    Task<int>[] downloadTasks = downloadTasksQuery.ToArray();
    
  4. Call WhenAny na zbiorem zadań.WhenAnyreturns a Task(Of Task(Of Integer)) or Task<Task<int>>.Oznacza to WhenAny zwraca zadanie, którego wynikiem jest pojedyncza Task(Of Integer) lub Task<int> kiedy jest oczekiwany.Że jedno zadanie jest to pierwsze zadanie w kolekcji, aby zakończyć.Przydzielonego zadania, który wygrał firstFinishedTask.Typ firstFinishedTask jest Task<TResult> gdzie TResult jest liczbą całkowitą, ponieważ jest zwracany typ ProcessURLAsync.

    ' ***Call WhenAny and then await the result. The task that finishes 
    ' first is assigned to firstFinishedTask.
    Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
    
    // ***Call WhenAny and then await the result. The task that finishes 
    // first is assigned to firstFinishedTask.
    Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
    
  5. W tym przykładzie interesuje tylko zadania, który kończy się po raz pierwszy.W związku z tym, użyj CancellationTokenSource.Cancel Aby anulować pozostałych zadań.

    ' ***Cancel the rest of the downloads. You just want the first one.
    cts.Cancel()
    
    // ***Cancel the rest of the downloads. You just want the first one.
    cts.Cancel();
    
  6. Wreszcie, czekają na firstFinishedTask do pobierania długości pobieranej zawartości.

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

Aby zweryfikować, że różne pliki do pobrania zakończyć po raz pierwszy, należy uruchomić program kilka razy.

Kompletny przykład

Poniższy kod jest kompletny plik 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 & "Download complete."

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

        Catch ex As Exception
            resultsTextBox.Text &= vbCrLf & "Download 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()

        '' Comment out or delete the loop.
        ''For Each url In urlList
        ''    ' GetAsync returns a Task(Of HttpResponseMessage). 
        ''    ' Argument ct carries the message if the Cancel button is chosen. 
        ''    ' Note that the Cancel button can cancel all remaining downloads.
        ''    Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

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

        ''    resultsTextBox.Text &=
        ''        String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, urlContents.Length)
        ''Next

        ' ***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 ToArray to execute the query and start the download tasks. 
        Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()

        ' ***Call WhenAny and then await the result. The task that finishes 
        ' first is assigned to firstFinishedTask.
        Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)

        ' ***Cancel the rest of the downloads. You just want the first one.
        cts.Cancel()

        ' ***Await the first completed task and display the results
        ' Run the program several times to demonstrate that different
        ' websites can finish first.
        Dim length = Await firstFinishedTask
        resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)
    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 downloaded website:  158856

' Download 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 CancelAfterOneTask
{
    public partial class MainWindow : Window
    {
        // Declare a System.Threading.CancellationTokenSource.
        CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }


        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the CancellationTokenSource.
            cts = new CancellationTokenSource();

            resultsTextBox.Clear();

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

            // Set the CancellationTokenSource to null when the download is complete.
            cts = null;
        }


        // You can still include a Cancel button if you want to.
        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
        }


        // Provide a parameter for the CancellationToken.
        async Task AccessTheWebAsync(CancellationToken ct)
        {
            HttpClient client = new HttpClient();

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

            // ***Comment out or delete the loop.
            //foreach (var url in urlList)
            //{
            //    // GetAsync returns a Task<HttpResponseMessage>. 
            //    // Argument ct carries the message if the Cancel button is chosen. 
            //    // ***Note that the Cancel button can cancel all remaining downloads.
            //    HttpResponseMessage response = await client.GetAsync(url, ct);

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

            //    resultsTextBox.Text +=
            //        String.Format("\r\nLength of the downloaded string: {0}.\r\n", urlContents.Length);
            //}

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

            // ***Use ToArray to execute the query and start the download tasks. 
            Task<int>[] downloadTasks = downloadTasksQuery.ToArray();

            // ***Call WhenAny and then await the result. The task that finishes 
            // first is assigned to firstFinishedTask.
            Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

            // ***Cancel the rest of the downloads. You just want the first one.
            cts.Cancel();

            // ***Await the first completed task and display the results. 
            // Run the program several times to demonstrate that different
            // websites can finish first.
            var length = await firstFinishedTask;
            resultsTextBox.Text += String.Format("\r\nLength of the downloaded website:  {0}\r\n", length);
        }


        // ***Bundle the processing steps for a website into one async method.
        async Task<int> ProcessURLAsync(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;
        }


        // Add a method that creates a list of web addresses.
        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "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;
        }
    }
    // Sample output:

    // Length of the downloaded website:  158856

    // Download 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