次の方法で共有


完了時での複数のタスクとプロセスの実行 (C# および Visual Basic)

Task.WhenAnyを使用して、プロセスはなく、呼び出される順序で完了時に複数のタスクを同時に開始し、一つずつ処理できます。

次の例では、タスクのコレクションを作成するためにクエリが使用されます。各タスクは、指定した Web サイトのコンテンツをダウンロードします。while ループの各反復で、WhenAny への呼び出しは、必要なダウンロードを最初に終了タスクのコレクションのタスクを返します。タスクはコレクションから削除され、処理されます。コレクションが実行されるまでループの繰り返しにこれ以上のタスクは含まれません。

[!メモ]

例を実行するには、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. [ソリューション エクスプローラー] では、[ProcessTasksAsTheyFinish] のプロジェクトのショートカット メニューを開き、[スタートアップ プロジェクトに設定] を選択します。

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

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

  6. プロジェクトをダウンロードした長さが同じ順序で常に表示されないことを確認する複数回実行します。

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

例のビルド

この例では、完了後の残りのタスクのキャンセル (C# および Visual Basic) で開発した追加し、同じ UI をコードに使用します。

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

[CancelAfterOneTask] のプロジェクトが既に実行されたときにタスクのコレクションを作成するクエリが含まれます。次のコードの ProcessURLAsync に対する各呼び出しは TResult が整数である Task<TResult> を返します。

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

プロジェクトのファイル MainWindow.xaml.vb または MainWindow.xaml.cs で、AccessTheWebAsync のメソッドに次の変更を行います。

  • ToArray<TSource>の代わりに Enumerable.ToList<TSource> を適用してクエリを実行します。

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
    
    List<Task<int>> downloadTasks = downloadTasksQuery.ToList();
    
  • コレクションの各タスクの次の手順を実行中のループを追加します。

    1. WhenAny の呼び出しのダウンロードが終了コレクションの最初のタスクを識別するために待機します。

      Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
      
      Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
      
    2. コレクションからタスクを削除。

      downloadTasks.Remove(firstFinishedTask)
      
      downloadTasks.Remove(firstFinishedTask);
      
    3. firstFinishedTaskを待って、ProcessURLAsyncの呼び出しによって返される。firstFinishedTask の変数は TReturn が整数の Task<TResult> です。次の例に示すように、[タスクが既に完了していますが、ダウンロードした Web サイトの長さを取得するように待機します。

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

プロジェクトをダウンロードした長さが同じ順序で常に表示されないことを確認する複数回実行する必要があります。

Caution メモ注意

ループで一部のタスクに関係する問題を解決するには、を WhenAny 例に示すように使用できます。ただし、他の方法では、複数のタスクが処理する場合よりも効率的です。詳細については、" "を参照してください。タスクを完了したとして処理

コード例全体

次のコードは、サンプルの 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 & "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.

参照

関連項目

WhenAny

概念

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

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

その他の技術情報

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