Hoje vou apresentar o recurso streams assíncronos incluído na versão 8.0 da linguagem C#. |
A linguagem C# apresenta suporte a métodos assíncronos e a métodos iteradores mas não tinha suporte para métodos iteradores assíncronos.
Isso mudou a partir da versão 8.0 quando foi incluído o recurso streams assíncronos.
A Interface IEnumerable permite realizar iterações sobre um tipo e se podemos iterar sobre uma lista é porque ela implementa IEnumerable.
Dessa forma o código a seguir :
var meses =
new List<string>() { "janeiro",
"fevereiro", "março", "abril"}; foreach (var mes in meses) { Console.WriteLine(mes); } |
É possível pois a classe List<T> implementa a interface IEnumerable que implementa a interface IEnumerator que retornar um enumerador que pode ser usado para iterar através da coleção.
Ocorre que em um cenário real geralmente não temos a lista pronto para ser consumida mas obtemos a lista ou parte dela através da chamada de um método.
Quando obtemos um elemento por vez da lista podemos usar a instrução yield que implementa um iterador de forma direta de forma a gerar os valores um a um da lista.
Desta forma estamos criando um tipo iterável que retorna um IEnumerable como mostrar o trecho de código a seguir:
static private IEnumerable<string> GeraMeses() { yield return "janeiro"; yield return "fevereiro"; yield return "março"; yield return "abril";
} |
Note que o que temos aqui na verdade é uma sequência de dados ou um stream e que estamos iterando sobre esse stream de dados de forma síncrona.
Mas e se desejarmos gerar os nomes dos meses de forma assíncrona ?
Usando streams assíncronos
Para poder tentar gerar os nomes dos meses de forma assíncrona devemos tornar o método assíncrono usando o modificador async e retornando um Task de IEnumerable, e, usar um await para simular uma tarefa :
static private async Task<IEnumerable<string>> GeraMeses() { yield return "janeiro";
yield return "fevereiro"; yield return "março"; yield return "abril";
} |
Ao tentar fazer
isso teremos um erro que indica que não podemos iterar o tipo
Task porque o iterável é a interface
IEnumerable e
task não contem uma definição para GetEnumerator.
É aqui que entram
os streams assíncronos introduzidos no C# 8.0.
Podemos usar streams assíncronos para criar tipos enumeráveis que geram dados de
forma assíncrona.
Para isso temos que cumprir 3 exigências :
1- O método deve ser assíncrono (async/await);
2- O tipo de retorno do método deve ser IAsyncEnumerable<T>;
3- O corpo do método deve conter pelo menos um yield return;
Aqui a interface IAsyncEnumerable expõe um
enumerador que oferece iteração assíncrona sobre valores de um tipo
especificado, e, a instrução return yield retornam
elementos sucessivos no stream assíncrono.
Este recurso esta disponível no .NET 5.0, .NET Core
3.0 e no .NET Standard 2.1.
Vejamos então como aplicar isso ao nosso método GeraMeses
para realizar o acesso assíncrono ao stream de meses.
static private async IAsyncEnumerable<IEnumerable<string> GeraMeses() { yield return "janeiro";
yield return "fevereiro"; yield return "março"; yield return "abril";
} |
Aqui usamos a
interface IAsyncEnumerable no lugar de
Task<IEnumerable> e invocamos o método usando um
await na frente de foreach.
Dessa forma agora temos um Enumerable assíncrono
que gera valores de forma assíncrona.
Os exemplos que eu
usei foram bem simples de forma a facilitar o entendimento. No entanto este
recurso geralmente é usado em cenário com acesso remoto para obter valores de um
serviço web onde temos uma grande quantidade de dados que serão
processados de forma gradual.
E estamos
conversados...
"E, ao pôr do
sol, todos os que tinham enfermos de várias doenças lhos traziam; e, pondo as
mãos sobre cada um deles, 'Jesus' os curava."
Lucas 4:40
Referências:
C# 8.0 - A instrução switch - Macoratti
C# - Programação Funcional - Exemplos - Macoratti
C# 8.0 - As novidades da nova versão - Macoratti
C# - Coleções Imutáveis - Macoratti
C# - O que há de novo com o C# 9.0 - Macoratti
C# 9.0 - Apresentando Records - Macoratti.net
C# - Sintaxe e conceitos básicos - Macoratti
C# - Os 10 Erros mais comuns dos iniciantes - Macoratti
C# - Otimizando o código - Macoratti