Aracılığıyla paylaş


Zaman Uyumsuz Birden Çok Görevi Başlatma ve Görevleri Tamamlandıkça İşleme (C# ve Visual Basic)

Task.WhenAny öğesini kullanarak, aynı anda birden çok görev başlatabilir ve bunları başlatılma sırasıyla işlemek yerine tamamlandıkça birer birer işleyebilirsiniz.

Aşağıdaki örnek, bir görev koleksiyonu oluşturmak için bir sorgu kullanmaktadır.Her görev, belirtilen bir web sitesinin içeriklerini karşıdan yükler.While döngüsünün her yinelemesinde, WhenAny bekletilen çağrısı kendi indirmesi biten görev koleksiyonundaki görevleri döndürür.Bu görev koleksiyondan kaldırılır ve işlenir.Döngü koleksiyonda artık başka görev kalmayana kadar yinelenir.

[!NOT]

Örnekleri çalıştırmak için bilgisayarınızda Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 for Windows Desktop, Windows için Visual Studio Express 2013 veya .NET Framework 4.5 ya da 4.5.1 yüklü olmalıdır.

Örneği İndirme

Zaman Uyumsuz Örneği: Uygulamanıza İnce Ayar Yapma bölümünden Windows Presentation Foundation (WPF) projesinin tamamını indirebilir ve ardından şu adımları izleyebilirsiniz.

  1. Karşıdan yüklenen sıkıştırılmış dosyayı açın ve daha sonra Visual Studio'yu başlatın.

  2. Menü çubuğunda, Dosya, , Proje/Çözüm seçeneklerini belirleyin.

  3. Proje aç iletişim kutusunda, açtığınız örnek kodu barındıran klasörü açın, ardından AsyncFineTuningCS veya AsyncFineTuningVB için çözüm (.sln) dosyasını açın.

  4. Çözüm Gezgini'nde ProcessTasksAsTheyFinish projesinin kısayol menüsünü açın arından Başlangıç Projesi Olarak Ayarla öğesini seçin.

  5. Projeyi çalıştırmak için F5 tuşuna basın.

    Projeyi hata ayıklama olmadan çalıştırmak için Ctrl + F5 tuşlarını seçin.

  6. İndirilen uzunlukları her zaman aynı sırada görüntülenmediğini doğrulamak için projeyi birkaç kez çalıştırın.

Projeyi indirmek istemiyorsanız, bu konunun sonunda MainWindow.xaml.vb ve MainWindow.xaml.cs dosyalarını gözden geçirebilirsiniz.

Örneği Oluşturma

Bu örnek, Bir Görev Tamamlandıktan Sonra Geri Kalan Zaman Uyumsuz Görevleri İptal Etme (C# ve Visual Basic) içinde geliştirilen ve aynı arabirimi kullanan koda eklenir.

Örneği kendiniz oluşturmanız için, "Örneği İndirme" bölümündeki yönergeleri adım adım uygulayın, fakat Başlangıç Projesi olarak CancelAfterOneTask öğesini seçin.Bu konudaki değişiklikleri bu projedeki AccessTheWebAsync yöntemine ekleyin.Değişiklikler, yıldız işareti ile işaretlenir.

CancelAfterOneTask projesi, zaten çalıştırıldığında bir görev koleksiyonu oluşturan bir sorgu içerir.Şu koddaki ProcessURLAsync öğesine yapılan her çağrı bir Task getirir; burada TResult bir tamsayıdır.

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

Projenin MainWindow.xaml.vb veya MainWindow.xaml.cs dosyasında AccessTheWebAsync yönteminde aşağıdaki değişiklikleri yapın.

  • ToArray``1 yerine Enumerable.ToList``1 uygulayarak sorguyu yürütün.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
    
    List<Task<int>> downloadTasks = downloadTasksQuery.ToList();
    
  • Koleksiyondaki her görev için şu adımları gerçekleştiren bir while döngüsü ekleyin.

    1. Karşıdan yüklemesini tamamlamak için koleksiyondaki ilk görevi tanımlamak üzere WhenAny öğesine bir çağrı yapılmasını bekler.

      Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
      
      Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
      
    2. O nesneyi koleksiyondan kaldırır.

      downloadTasks.Remove(firstFinishedTask)
      
      downloadTasks.Remove(firstFinishedTask);
      
    3. ProcessURLAsync öğesine yapılan bir çağrı tarafından getirilen firstFinishedTask öğesini bekler.firstFinishedTask değişkeni bir Taskdir; burada TReturn bir tamsayıdır.Bu görev zaten tamamlandı, ancak karşıdan yüklenen Web sitesi uzunluğunu aşağıdaki örnekte gösterildiği gibi almak için bekliyorsunuz.

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

İndirilen uzunlukların her zaman aynı sırada görüntülenmediğini doğrulamak için projeyi birkaç kez çalıştırmalısınız.

Uyarı notuUyarı

Örnekte açıklandığı üzere döngü içinde WhenAny kullanımı, az sayıda görev içeren sorunlar için iyidir.Ancak işlemeniz gereken çok sayıda görev varsa diğer yaklaşımlar daha etkilidir.Daha fazla bilgi ve örnek için bkz. Görevleri tamamlandı olarak işleme.

Tam Örnek

Aşağıdaki kod, örnek için MainWindow.xaml.vb veya MainWindow.xaml.cs dosyasının tam metnidir.Yıldız işaretleri, bu örnek için eklenen öğeleri işaretler.

System.Net.Http için bir başvuru eklemeniz gerektiğini unutmayın.

Zaman Uyumsuz Örnek: Uygulamanıza İnce Ayar Yapma içinden projeyi karşıdan yükleyebilirsiniz.

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

Ayrıca bkz.

Başvuru

WhenAny``1

Kavramlar

Async Uygulamanızda Hassas Ayar Yapma (C# ve Visual Basic)

Async ve Await ile Zaman Uyumsuz Programlama (C# ve Visual Basic)

Diğer Kaynaklar

Zaman Uyumsuz Örneği: Uygulamanıza İnce Ayar Yapma