完了後の残りのタスクのキャンセル (C# および Visual Basic)

CancellationTokenとともに Task.WhenAny のメソッドを使用して、1 種類のタスクが完了すると、残りすべてのタスクをキャンセルできます。WhenAny のメソッドは、タスクのコレクションである引数を受け取ります。メソッドは、すべてのタスクを起動し、単一のタスクを返します。一つのタスクはコレクションのすべてのタスクが完了すると完了します。

この例では、タスクのコレクションから、残りのタスクをキャンセル最初のタスクに保持に WhenAny とともにキャンセル トークンを使用する方法を示します。各タスクは、Web サイトのコンテンツをダウンロードします。例が完了すると、のダウンロードのコンテンツの長さを表示、他のダウンロードをクリックします。

[!メモ]

例を実行するには、Visual Studio 2012 Visual Studio には、Windows のデスクトップの 2012 を表します。、またはのコンピューターに .NET Framework 4.5 がインストールされている必要があります。

例のダウンロード

Windows Presentation Foundation (WPF) の完全なプロジェクトをから 単一の例: アプリケーションの微調整 ダウンロードし、これらの手順を実行します。

  1. ダウンロードした展開し、を Visual Studio 2012ファイルを起動します。

  2. メニュー バーで [ファイル][開く][プロジェクト/ソリューション] の順に選択します。

  3. [プロジェクトを開く] のダイアログ ボックスで、配置した保持し、AsyncFineTuningCS または AsyncFineTuningVB のソリューション (.sln) ファイルを開くコード例をフォルダーを開きます。

  4. [ソリューション エクスプローラー] では、[CancelAfterOneTask] のプロジェクトのショートカット メニューを開き、[スタートアップ プロジェクトに設定] を選択します。

  5. プロジェクトを実行するには、F5 キーを選択します。

    デバッグをプロジェクトを実行するには、F5 キー キーを選択します。

  6. 異なるプログラムをダウンロードが完了することを検証する複数回実行します。

プロジェクトをダウンロードしない場合は、このトピックの最後に MainWindow.xaml.vb または MainWindow.xaml.cs ファイルを確認できます。

例のビルド

このトピックの例では、タスク リストをキャンセルする タスクまたはタスクの一覧のキャンセル (C# および Visual Basic) で作成したプロジェクトに追加します。この例では [キャンセル] のボタンが明示的に使用されませんが、同じ UI を使用します。

例を、独自方法のビルド、ダウンロード "例" のセクションの指示に従いますが、[スタートアップ プロジェクト] として [CancelAListOfTasks] を選択します。そのプロジェクトにこのトピックの変更を追加します。

[CancelAListOfTasks] のプロジェクトのファイル MainWindow.xaml.vb または MainWindow.xaml.cs で、AccessTheWebAsync のループを実行してから次遷移の非同期メソッドとの各 Web サイト用の処理を開始します。

' ***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;
}

AccessTheWebAsyncでは、この例では、クエリ ToArray<TSource> のメソッドとタスクの配列を作成し、起動に WhenAny のメソッドを使用します。配列への WhenAny のアプリケーションは、予期したときにタスクの完了に到達する最初のタスクに評価する一つのタスクを返します。

AccessTheWebAsyncの次の変更を行います。アスタリスクは、コード ファイルの変更について説明します。

  1. コメントにしたり、ループを削除します。

  2. 実行されると、一般的なタスクのコレクションを生成するクエリを作成します。ProcessURLAsync に対する各呼び出しは TResult が整数である Task<TResult> を返します。

    ' ***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. クエリを実行し、タスクを開始するには ToArray を呼び出します。次の手順で WhenAny のメソッドのアプリケーションは、クエリを実行して、が ToArrayを使用せずにタスクを起動し、他のメソッドは実行されていません。最も安全な方法は、クエリの実行を明示的に変換することです。

    ' ***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. タスクのコレクションでは WhenAny。WhenAny は Task(Of Task(Of Integer)) か Task<Task<int>>を返します。つまり、WhenAny は待ったら一つの Task(Of Integer) か Task<int> に評価するタスクを返します。その一つのタスクが終了するまでコレクションの最初のタスクです。最初に終了したタスクは firstFinishedTaskに再配置。firstFinishedTask の型は、ProcessURLAsyncの戻り値の型である TResult が整数の Task<TResult> です。

    ' ***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. この例では、最初に終了したタスクにのみ焦点を当てています。したがって、残りのタスクをキャンセルするには CancellationTokenSource.Cancel を使用します。

    ' ***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. 最後に、ダウンロード コンテンツの長さを取得するには firstFinishedTask 待ちます。

    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);
    

異なるプログラムをダウンロードが完了することを検証する複数回実行します。

コード例全体

次のコード例の完全な MainWindow.xaml.vb または MainWindow.xaml.cs ファイルです。マークは、この例のために追加された要素たしてアスタリスク記号を付けます。

System.Net.Httpの参照を追加する必要があることに注意してください。

プロジェクトをから 単一の例: アプリケーションの微調整ダウンロードできます。

' 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.
}

参照

関連項目

WhenAny

概念

非同期アプリケーションの微調整 (C# および Visual Basic)

Async および Await を使用した非同期プログラミング (C# および Visual Basic)

その他の技術情報

単一の例: アプリケーションの微調整