Compartir a través de


Iniciar varias tareas asincrónicas y procesarlas a medida que se completan (Visual Basic)

Task.WhenAnyMediante , puede iniciar varias tareas al mismo tiempo y procesarlas una por una a medida que se completan en lugar de procesarlas en el orden en que se inician.

En el ejemplo siguiente se usa una consulta para crear una colección de tareas. Cada tarea descarga el contenido de un sitio web especificado. En cada iteración de un bucle while, una llamada awaited a WhenAny devuelve la tarea en la colección de tareas que termine primero su descarga. Esa tarea se quita de la colección y se procesa. El bucle se repite hasta que la colección no contiene más tareas.

Nota:

Para ejecutar los ejemplos, debe tener Visual Studio 2012 o versiones posteriores y .NET Framework 4.5 o posterior instalado en el equipo.

Descarga del ejemplo

Puede descargar el proyecto completo de Windows Presentation Foundation (WPF) de Async Sample: Fine Tuning Your Application y luego siga estos pasos.

  1. Descomprima el archivo que descargó e inicie Visual Studio.

  2. En la barra de menús, elija Archivo, Abrir, Proyecto o solución.

  3. En el cuadro de diálogo Abrir proyecto , abra la carpeta que contiene el código de ejemplo que descomprimió y, a continuación, abra el archivo de solución (.sln) para AsyncFineTuningVB.

  4. En el Explorador de soluciones, abra el menú contextual del proyecto ProcessTasksAsTheyFinish y elija Establecer como proyecto de inicio.

  5. Elija la tecla F5 para ejecutar el proyecto.

    Presione las teclas Ctrl+F5 para ejecutar el proyecto sin depurarlo.

  6. Ejecute el proyecto varias veces para comprobar que las longitudes descargadas no siempre aparecen en el mismo orden.

Si no desea descargar el proyecto, puede revisar el archivo MainWindow.xaml.vb al final de este tema.

Creación del ejemplo

En este ejemplo se agrega al código que se desarrolla en Cancelar tareas asincrónicas restantes después de que se complete una (Visual Basic) y utiliza la misma interfaz de usuario.

Para compilar el ejemplo, paso a paso, siga las instrucciones de la sección "Descargar el ejemplo", pero elija CancelAfterOneTask como proyecto de inicio. Agregue los cambios en este tema al método AccessTheWebAsync de ese proyecto. Los cambios se marcan con asteriscos.

El proyecto CancelAfterOneTask ya incluye una consulta que, cuando se ejecuta, crea una colección de tareas. Cada llamada a ProcessURLAsync en el código siguiente devuelve un Task<TResult> donde TResult es un entero.

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

En el archivo MainWindow.xaml.vb del proyecto, realice los siguientes cambios en el AccessTheWebAsync método .

  • Ejecute la consulta aplicando Enumerable.ToList en lugar de ToArray.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()  
    
  • Agregue un bucle while que realice los pasos siguientes para cada tarea de la colección.

    1. Espera una llamada a WhenAny para identificar la primera tarea en la colección para finalizar su descarga.

      Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)  
      
    2. Quita la tarea de la colección.

      downloadTasks.Remove(finishedTask)  
      
    3. Espera finishedTask, que se devuelve mediante una llamada a ProcessURLAsync. La finishedTask variable es un Task<TResult> donde TReturn es un entero. La tarea ya está completa, pero la espera para recuperar la longitud del sitio web descargado, como se muestra en el ejemplo siguiente.

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

Debe ejecutar el proyecto varias veces para comprobar que las longitudes descargadas no siempre aparecen en el mismo orden.

Precaución

Puede usar WhenAny en un bucle, como se describe en el ejemplo, para resolver problemas que implican un pequeño número de tareas. Sin embargo, otros enfoques son más eficaces si tiene un gran número de tareas que procesar. Para obtener más información y ejemplos, vea Procesamiento de tareas a medida que se completan.

Ejemplo completo

El código siguiente es el texto completo del archivo MainWindow.xaml.vb para el ejemplo. Los asteriscos marcan los elementos que se agregaron para este ejemplo.

Observe que debe agregar una referencia para System.Net.Http.

Puede descargar el proyecto desde Async Sample: Ajuste de la aplicación.

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

Consulte también