Spuštění několika asynchronních úloh a jejich zpracování při jejich dokončení (Visual Basic)

Pomocí nich Task.WhenAnymůžete současně spouštět více úkolů a zpracovávat je po jednom, protože jsou dokončené, a ne je zpracovávat v pořadí, ve kterém jsou spuštěné.

Následující příklad používá dotaz k vytvoření kolekce úloh. Každý úkol stáhne obsah zadaného webu. V každé iteraci smyčky while vrátí čekané volání WhenAny úkol v kolekci úkolů, který dokončí stahování jako první. Tato úloha se odebere z kolekce a zpracuje se. Smyčka se opakuje, dokud kolekce neobsahuje žádné další úkoly.

Poznámka:

Abyste mohli spustit příklady, musíte mít na počítači nainstalovanou sadu Visual Studio 2012 nebo novější a rozhraní .NET Framework 4.5 nebo novější.

Stažení příkladu

Kompletní projekt Windows Presentation Foundation (WPF) si můžete stáhnout z asynchronní ukázky: Vyladění aplikace a pak postupujte podle těchto kroků.

  1. Dekomprimujte soubor, který jste stáhli, a spusťte Visual Studio.

  2. Na řádku nabídek zvolte Soubor, Otevřít, Projekt nebo Řešení.

  3. V dialogovém okně Otevřít projekt otevřete složku obsahující ukázkový kód, který jste dekompprimovali, a pak otevřete soubor řešení (.sln) pro AsyncFineTuningVB.

  4. V Průzkumníku řešení otevřete kontextovou nabídku projektu ProcessTasksAsTheyFinish a pak zvolte Nastavit jako spouštěcí projekt.

  5. Zvolte klávesu F5, aby se projekt spustil.

    Pokud chcete projekt spustit bez ladění, zvolte klávesy Ctrl+F5.

  6. Spusťte projekt několikrát, abyste ověřili, že se stažené délky nezobrazují vždy ve stejném pořadí.

Pokud si projekt nechcete stáhnout, můžete si projít MainWindow.xaml.vb soubor na konci tohoto tématu.

Sestavení příkladu

Tento příklad přidá kód vyvinutý ve funkci Zrušit zbývající asynchronní úlohy po dokončení jednoho (Visual Basic) a použije stejné uživatelské rozhraní.

Pokud chcete sestavit příklad sami, postupujte krok za krokem podle pokynů v části "Stažení příkladu", ale jako projekt StartUp zvolte CancelAfterOneTask. Přidejte změny v tomto tématu do AccessTheWebAsync metody v tomto projektu. Změny jsou označené hvězdičkami.

Projekt CancelAfterOneTask již obsahuje dotaz, který při spuštění vytvoří kolekci úkolů. Každé volání ProcessURLAsync v následujícím kódu vrátí Task<TResult>, kde TResult je celé číslo.

Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
    From url In urlList Select ProcessURLAsync(url, client, ct)

V MainWindow.xaml.vb souboru projektu proveďte následující změny metody AccessTheWebAsync .

  • Spusťte dotaz tak, že použijete Enumerable.ToList místo ToArray.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
    
  • Přidejte smyčku While, která provádí následující kroky pro každou úlohu v kolekci.

    1. Čeká na volání k WhenAny identifikaci prvního úkolu v kolekci, aby se dokončilo stahování.

      Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
      
    2. Odebere tuto úlohu z kolekce.

      downloadTasks.Remove(finishedTask)
      
    3. Čeká na finishedTask, který je vrácen pomocí volání ProcessURLAsync. Proměnná finishedTask je Task<TResult>, kde TReturn je celé číslo. Úkol je již dokončený, ale očekáváte, že načte délku staženého webu, jak ukazuje následující příklad.

      Dim length = Await finishedTask
      resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)
      

Projekt byste měli spustit několikrát, abyste ověřili, že se stažené délky nezobrazí vždy ve stejném pořadí.

Upozornění

Ve smyčce můžete použít WhenAny, jak je popsáno v příkladu, k řešení problémů, které zahrnují malý počet úkolů. Pokud ale máte velký počet úkolů ke zpracování, jsou další přístupy efektivnější. Další informace a příklady najdete v tématu Zpracování úloh při jejich dokončení.

Kompletní příklad

Následující kód je úplný text souboru MainWindow.xaml.vb příkladu. Hvězdičky označují prvky přidané v tomto příkladu.

Všimněte si, že je nutné přidat odkaz pro System.Net.Http.

Projekt si můžete stáhnout z Async Sample: Doladění vaší aplikace.

' 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 finishedTask 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(finishedTask)

            ' ***Await the first completed task and display the results.
            Dim length = Await finishedTask
            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/library/hh290138.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/dd470362.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com/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.

Viz také