Condividi tramite


Avviare più attività asincrone ed elaborarle man mano che vengono completate (Visual Basic)

Usando Task.WhenAny, è possibile avviare più attività contemporaneamente ed elaborarle una alla volta man mano che vengono completate anziché elaborarle nell'ordine in cui vengono avviate.

Nell'esempio seguente viene utilizzata una query per creare una raccolta di attività. Ogni attività scarica il contenuto di un sito Web specificato. In ogni iterazione di un ciclo while, una chiamata attesa a WhenAny restituisce il task nella raccolta di task che completa per primo il download. Tale attività viene rimossa dalla raccolta ed elaborata. Il ciclo si ripete fino a quando la raccolta non contiene altre attività.

Annotazioni

Per eseguire gli esempi, è necessario che Nel computer sia installato Visual Studio 2012 o versione successiva e .NET Framework 4.5 o versione successiva.

Download dell'esempio

È possibile scaricare il progetto Windows Presentation Foundation (WPF) completo da Esempio asincrono: Ottimizzazione dell'applicazione e quindi seguire questa procedura.

  1. Decomprimere il file scaricato e quindi avviare Visual Studio.

  2. Sulla barra dei menu scegliere File, Apri, Progetto/Soluzione.

  3. Nella finestra di dialogo Apri progetto aprire la cartella contenente il codice di esempio decompresso e quindi aprire il file della soluzione (.sln) per AsyncFineTuningVB.

  4. In Esplora soluzioni aprire il menu di scelta rapida per il progetto ProcessTasksAsTheyFinish e quindi scegliere Imposta come progetto di avvio.

  5. Scegliere il tasto F5 per eseguire il progetto.

    Scegliere i tasti CTRL+F5 per eseguire il progetto senza eseguirne il debug.

  6. Eseguire il progetto più volte per verificare che le lunghezze scaricate non vengano sempre visualizzate nello stesso ordine.

Se non si vuole scaricare il progetto, è possibile esaminare il file di MainWindow.xaml.vb alla fine di questo argomento.

Compilazione dell'esempio

Questo esempio amplia il codice sviluppato in Annulla attività asincrone rimanenti dopo un'operazione completata (Visual Basic) e utilizza la stessa interfaccia utente.

Per compilare manualmente l'esempio passo dopo passo, seguire le istruzioni nella sezione "Download dell'Esempio", ma scegliere CancelAfterOneTask come progetto di avvio. Aggiungi le modifiche di questo argomento al metodo AccessTheWebAsync in quel progetto. Le modifiche sono contrassegnate con asterischi.

Il progetto CancelAfterOneTask include già una query che, quando eseguita, crea una raccolta di attività. Ogni chiamata a ProcessURLAsync nel codice seguente restituisce un oggetto Task<TResult> dove TResult è un numero intero.

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

Nel file MainWindow.xaml.vb del progetto apportare le modifiche seguenti al AccessTheWebAsync metodo .

  • Eseguire la query applicando Enumerable.ToList invece di ToArray.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()  
    
  • Aggiungere un ciclo while che esegue i seguenti passaggi per ogni attività nella raccolta.

    1. Attende una chiamata a WhenAny per identificare la prima attività nella raccolta che completa il suo scaricamento.

      Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)  
      
    2. Rimuove l'attività dalla raccolta.

      downloadTasks.Remove(finishedTask)  
      
    3. Attende finishedTask, che è restituito da una chiamata a ProcessURLAsync. La finishedTask variabile è un Task<TResult> oggetto dove TReturn è un numero intero. L'attività è già stata completata, ma si attende che venga recuperata la lunghezza del sito Web scaricato, come illustrato nell'esempio seguente.

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

È consigliabile eseguire il progetto più volte per verificare che le lunghezze scaricate non vengano sempre visualizzate nello stesso ordine.

Attenzione

È possibile usare WhenAny in un ciclo, come descritto nell'esempio, per risolvere i problemi che coinvolgono un numero ridotto di attività. Tuttavia, altri approcci sono più efficienti se si dispone di un numero elevato di attività da elaborare. Per altre informazioni ed esempi, vedere Elaborazione delle attività man mano che vengono completate.

Esempio completo

Il codice seguente è il testo completo del file MainWindow.xaml.vb per l'esempio. Gli asterischi contrassegnano gli elementi aggiunti per questo esempio.

Si noti che è necessario aggiungere un riferimento per System.Net.Http.

È possibile scaricare il progetto da Esempio asincrono: Ottimizzazione dell'applicazione.

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

Vedere anche