Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Observação
Apenas a partir do EF6 - As funcionalidades, APIs, etc. discutidas nesta página foram introduzidas no Entity Framework 6. Se estiver a usar uma versão anterior, parte ou toda a informação não se aplica.
O EF6 introduziu suporte para consulta e gravação assíncronas usando as palavras-chave async e await que foram introduzidas no .NET 4.5. Embora nem todas as aplicações possam beneficiar da assíncronia, esta pode ser usada para melhorar a resposta do cliente e a escalabilidade do servidor ao lidar com tarefas de longa duração, com rede ou I/O limitadas.
Quando realmente usar assíncrono
O objetivo deste guia é introduzir os conceitos assíncronos de uma forma que facilite a observação da diferença entre execução de programas assíncronas e síncronas. Este guia não pretende ilustrar nenhum dos cenários-chave em que a programação assíncrona oferece benefícios.
A programação assíncrona foca-se principalmente em libertar o thread gerido atual (thread a correr código .NET) para realizar outros trabalhos enquanto espera por uma operação que não exija tempo de computação de um thread gerido. Por exemplo, enquanto o motor de base de dados processa uma consulta, não há nada a fazer com código .NET.
Em aplicações cliente (WinForms, WPF, etc.) o thread atual pode ser usado para manter a interface responsiva enquanto a operação assíncrona é realizada. Em aplicações servidor (ASP.NET etc.), a thread pode ser usada para processar outros pedidos recebidos – isto pode reduzir o uso de memória e/ou aumentar o rendimento do servidor.
Na maioria das aplicações, usar assíncrono não terá benefícios notórios e pode até ser prejudicial. Usa testes, perfilagem e bom senso para medir o impacto do assíncrono no teu cenário particular antes de te comprometeres com ele.
Aqui estão mais alguns recursos para aprender sobre async.
- Visão geral de Brandon Bray sobre async/await em .NET 4.5
- Páginas de Programação Assíncrona na Biblioteca MSDN
Criar o modelo
Vamos usar o fluxo de trabalho Code First para criar o nosso modelo e gerar a base de dados, no entanto, a funcionalidade assíncrona funcionará com todos os modelos EF, incluindo os criados com o EF Designer.
- Crie uma aplicação de consola e chame-lhe AsyncDemo
- Adicionar o pacote NuGet do EntityFramework
- No Explorador de Soluções, clique com o botão direito no projeto AsyncDemo
- Selecionar Gerir Pacotes do NuGet...
- No diálogo Gestão de Pacotes NuGet, selecione o separador Online e escolha o pacote EntityFramework
- Clique em Instalar
- Adicionar uma classe Model.cs com a seguinte implementação
using System.Collections.Generic;
using System.Data.Entity;
namespace AsyncDemo
{
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public virtual List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
}
}
Criar um programa síncrono
Agora que temos um modelo EF, vamos escrever algum código que o use para realizar algum acesso a dados.
- Substitua o conteúdo de Program.cs pelo seguinte código
using System;
using System.Linq;
namespace AsyncDemo
{
class Program
{
static void Main(string[] args)
{
PerformDatabaseOperations();
Console.WriteLine("Quote of the day");
Console.WriteLine(" Don't worry about the world coming to an end today... ");
Console.WriteLine(" It's already tomorrow in Australia.");
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static void PerformDatabaseOperations()
{
using (var db = new BloggingContext())
{
// Create a new blog and save it
db.Blogs.Add(new Blog
{
Name = "Test Blog #" + (db.Blogs.Count() + 1)
});
Console.WriteLine("Calling SaveChanges.");
db.SaveChanges();
Console.WriteLine("SaveChanges completed.");
// Query for all blogs ordered by name
Console.WriteLine("Executing query.");
var blogs = (from b in db.Blogs
orderby b.Name
select b).ToList();
// Write all blogs out to Console
Console.WriteLine("Query completed with following results:");
foreach (var blog in blogs)
{
Console.WriteLine(" " + blog.Name);
}
}
}
}
}
Este código chama o PerformDatabaseOperations método que guarda um novo Blog na base de dados e depois recupera todos os Blogs da base de dados e imprime-os na Consola. Depois disso, o programa escreve uma citação do dia para a Consola.
Como o código é síncrono, podemos observar o seguinte fluxo de execução quando executamos o programa:
-
SaveChangescomeça a empurrar o novo Blog para a base de dados -
SaveChangesCompleta - A consulta para todos os blogs é enviada para a base de dados
- Os retornos e resultados das consultas são escritos para a Consola
- Citação do dia é escrita na Consola
Tornando-o assíncrono
Agora que temos o nosso programa a funcionar, podemos começar a usar as novas palavras-chave async e await. Fizemos as seguintes alterações à Program.cs
- Linha 2: A instrução using para o
System.Data.Entitynamespace dá-nos acesso aos métodos de extensão assíncrona do EF. - Linha 4: A instrução using para o namespace
System.Threading.Taskspermite-nos usar o tipoTask. - Linhas 12 e 18: Estamos a capturar uma tarefa que monitoriza o progresso de
PerformSomeDatabaseOperations(linha 12) e depois a bloquear a execução do programa para que esta tarefa seja concluída assim que todo o trabalho do programa estiver concluído (linha 18). - Linha 25: Atualizámos
PerformSomeDatabaseOperationspara ser marcado comoasynce devolver umTask. - Linha 35: Estamos agora a chamar a versão assíncrona de
SaveChangese a aguardar a sua conclusão. - Linha 42: Estamos agora a chamar a versão Assíncrona de
ToListe a aguardar o resultado.
Para uma lista abrangente dos métodos de extensão disponíveis no System.Data.Entity namespace, consulte a QueryableExtensions classe.
Também vais precisar de acrescentar using System.Data.Entity às tuas instruções de uso.
using System;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
namespace AsyncDemo
{
class Program
{
static void Main(string[] args)
{
var task = PerformDatabaseOperations();
Console.WriteLine("Quote of the day");
Console.WriteLine(" Don't worry about the world coming to an end today... ");
Console.WriteLine(" It's already tomorrow in Australia.");
task.Wait();
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static async Task PerformDatabaseOperations()
{
using (var db = new BloggingContext())
{
// Create a new blog and save it
db.Blogs.Add(new Blog
{
Name = "Test Blog #" + (db.Blogs.Count() + 1)
});
Console.WriteLine("Calling SaveChanges.");
await db.SaveChangesAsync();
Console.WriteLine("SaveChanges completed.");
// Query for all blogs ordered by name
Console.WriteLine("Executing query.");
var blogs = await (from b in db.Blogs
orderby b.Name
select b).ToListAsync();
// Write all blogs out to Console
Console.WriteLine("Query completed with following results:");
foreach (var blog in blogs)
{
Console.WriteLine(" - " + blog.Name);
}
}
}
}
}
Agora que o código é assíncrono, podemos observar um fluxo de execução diferente quando executamos o programa:
-
SaveChangescomeça a empurrar o novo Blog para a base de dados
Uma vez enviado o comando para a base de dados, não é necessário mais tempo de cálculo na thread gerida atual. OPerformDatabaseOperationsmétodo retorna (mesmo que ainda não tenha terminado a execução) e o fluxo do programa no método Main continua. -
A citação do dia é exibida na Consola
Como já não há trabalho a fazer no método Main, o thread gerido fica bloqueado naWaitchamada até que a operação da base de dados seja concluída. Quando estiver concluído, o restante da nossaPerformDatabaseOperationsserá executado. -
SaveChangesCompleta - A consulta para todos os blogs é enviada para a base de dados
Mais uma vez, o thread gerido fica livre para fazer outros trabalhos enquanto a consulta é processada na base de dados. Como todas as outras execuções já foram concluídas, a thread simplesmente para na chamada do método Wait. - Os retornos e resultados das consultas são escritos para a Consola
A conclusão
Agora vimos como é fácil utilizar os métodos assíncronos do EF. Embora as vantagens do assíncrono possam não ser muito evidentes numa simples aplicação de consola, estas mesmas estratégias podem ser aplicadas em situações onde atividades de longa duração ou ligadas à rede poderiam bloquear a aplicação ou levar um grande número de threads a aumentar o consumo de memória.