Processamento paralelo e assíncrono com Tasks

Published on by Jeferson Santos



Quando desenvolvemos para dispositivos móveis temos acesso, geralmente, a um subset do framework, deixando algumas implementações bastante limitadas.

No caso do Windows Phone 8.1 não há acesso às bibliotecas de paralelismo disponibilizadas no .NET, então, qual a melhor alternativa? Usar a classe Task.

Dentro da classe Task temos 2 funções que servem bem para o proposito de paralelismo:

  • Task.WhenAll
  • Task.WhenAny

Como exemplo vamos obter a partir de uma lista de strings suas respectivas representações em formato base64. No meio do método faremos um Task.Delay(2500) de forma que o método demore “pelo menos” 2,5s para concluir sua execução. O método é o seguinte:

private static async Task<string> ConvertToBase64Async(string msg)
{
    Console.WriteLine(string.Format("Started ==> {0} {1}", 
                                    DateTime.Now, 
                                    msg));
    var result = Convert.ToBase64String(Encoding.ASCII.GetBytes(msg));
    await Task.Delay(2500);
    Console.WriteLine(string.Format("Finished ==> {0} {1} >> {2}",
                                    DateTime.Now, 
                                    msg, 
                                    result));
    return result;
}

Task.WhenAll

Ao utilizar o WhenAll só vamos “liberar” a thread quando todos as Tasks que estão em execução forem finalizadas e retornarem seus respectivos valores.

var phrases = new List<string>
{
    "frase 1",
    "frase 2",
    "frase 3",
    "frase 4",
    "frase 5",
    "frase 6",
    "frase 7",
    "frase 8",
    "frase 9"
};

var enc = await Task.WhenAll(phrases.Select(q => ConvertToBase64Async(q)));
Console.WriteLine("**Finished**");

Neste exemplo, a linha “Finished” só vai ser exibida no console quando a última Task concluir sua execução. Antes disso, a thread que chamou a função fica em await.

Task.WhenAny

Ao utilizar o WhenAny a thread que o chamou é liberada, ou seja, sai de estado awaiting, assim que a primeira Task conclui sua execução.

var phrases = new List<string>
{
    "frase 1",
    "frase 2",
    "frase 3",
    "frase 4",
    "frase 5",
    "frase 6",
    "frase 7",
    "frase 8",
    "frase 9"
};

var enc = await Task.WhenAny(phrases.Select(q => ConvertToBase64Async(q)));
Console.WriteLine("**Finished**");

Mas e as outras Tasks? A execução continua em background, e paralelo a thread principal, então assim que forem concluindo, seus resultados são exibidos no console.

Quando usar?

Existem alguns cenários em que o uso de Tasks é bastante interessante como:
– Download de múltiplos assets em paralelo
– Carregamento progressivo de listas
– Múltiplas chamadas de serviços (por exemplo: atualização de dados de vários usuários, upload de uma lista de contatos, etc)