Estou vendo MVC4 agora. No momento, mexendo com a parte de chamadas assíncronas.
A primeira coisa é que queria construir algum exemplo simples, para entender melhor. Os que achei envolviam serviços e eu não queria criar um serviço para depois testar o que eu precisava.
Meu primeiro problema foi que o .NET 4.0 não conhece as keywords novas, async e await. Instalei o 4.5. Mas o Visual Studio 2010 não conhece o 4.5. Tentei até mudar no arquivo csproj em um editor de texto, mas não funcionou. Tive que instalar o VS2012 RC (http://www.microsoft.com/visualstudio/11/en-us). Se quer um conselho, não resolva instalar às 21h da sexta-feira.
Vamos à programação. Descobri que eu tinha que criar um método que chamasse qualquer outra coisa assíncrona. Pelo que li, já no 4.0 foram implementados métodos assíncronos no .NET. Tentei com chamada para a internet, mas retornava muito rápido.
O que resolvi usar foi leitura de um arquivo grande (precisava ser grande para testar o tempo, se realmente diminuiria). Meu computador é um core i5, 2,3 GHz, 4gB de ram, 64bit. Dois arquivos de mais ou menos 130mB foram usados.
Usei a classe StreamReader para ler, o método ReadToEndAsync. Para o método ser assíncrono, deve ser colocada a keyword async antes do tipo do método. Os métodos assíncronos que forem chamados dentro dele devem ser chamados com a keyword await antes, se for necessário aguardar o retorno deles para continuar.
Para o retorno do método, se usa a classe Task. Sozinha se for um void, como generic se houver algum tipo de retorno (passando o tipo do retorno real para a Task).
Meu método de leitura:
private async Task<String> readAsync(String filename)
{
var reader = new StreamReader(filename);
return await reader.ReadToEndAsync();
}
Chegou a me passar pela cabeça: se ele chama o método assíncrono e fica esperando o retorno, qual a diferença de fazer isso ou chamar o convencional mesmo? Eis a resposta:
var first = readAsync(firstFile);
await readAsync(secondFile);
await first;
Chamamos o primeiro, esperamos a execução do segundo, então esperamos a do primeiro (provavelmente ele já terá terminado). O primeiro fica executando ao mesmo tempo que o segundo. Uma economia de mais de 25% do tempo. Testei com 3 arquivos, cada qual em torno de 80mB. Quase 45% de ganho.
Problemas que esbarrei, para tomar cuidado:
- Tentei fazer com três arquivos, dos maiores. Recebi uma bela OutOfMemoryException. Precisa de um pouco de cuidado, não pedir muita coisa ao mesmo tempo;
- Tentei abrir o StreamReader com using*, mas ele fechou o arquivo antes de ler, por ser assíncrono. Então, cuidado quando faz dispose de objetos, sendo assíncrono você nunca sabe quando vai realmente usá-los, a menos que use await.
Meu ponto de partida foi este artigo: http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253813. A parte do timeout que cita não consegui fazer funcionar. Ele até retorna um erro de timeout, mas não redireciona para a view (nem trocando o tipo do erro para o que aparece na tela amarela) e executa o processo inteiro antes de retornar o timeout. Não me parece muito útil desse jeito.
* using (var reader = new StreamReader(filename))
Nenhum comentário:
Postar um comentário