DbContextPool no Asp.Net Core 2.0
http://blog.ralms.net/wp-content/uploads/2017/09/netcore.png
**
*DbContextPool *** esse novo recurso foi disponibilizado na versão do Asp.Net Core 2.0.
Esta API oferece suporte à infraestrutura Entity Framework Core.
A ideia principal é permitir a reutilização de instâncias do DbContext em um pool, que para muitos casos, iremos ter um aumento significativo de desempenho ao criar uma nova instância. Sem ter a necessidade de criar novamente uma nova instancia do objeto em memória.
Vamos criar um pequeno projeto pra testar essa nova API e entender melhor.
https://blog.ralms.net/imagens/techwiki/01.PNG
https://blog.ralms.net/imagens/techwiki/02.PNG
Vamos adicionar o pacote do ***Microsoft.EntityFrameworkCore.SqlServer 2.0.1
***para ser usado em nosso exemplo.
https://blog.ralms.net/imagens/techwiki/03.PNG
https://blog.ralms.net/imagens/techwiki/04.PNG
Substitua o conteúdo do seu Program.cs pelo conteúdo abaixo:
using System;
using System.Linq;
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace ExemploDbContextPooling
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext(
c => c.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=TechWiki;Integrated Security=True;"));
}
}
public class Program
{
private const int Threads = 50;
private const int Segundos = 8;
private static long _requisicoesProcessadas;
private static void Main()
{
var serviceCollection = new ServiceCollection();
new Startup().ConfigureServices(serviceCollection);
var serviceProvider = serviceCollection.BuildServiceProvider();
InicializarBanco(serviceProvider);
var stopWatch = new Stopwatch();
Resultados(TimeSpan.FromSeconds(Segundos), stopWatch);
Task.WhenAll(
Enumerable
.Range(0, Threads)
.Select(_ => SimularRequisicaosAsync(serviceProvider, stopWatch)));
Console.ReadKey();
}
private static void InicializarBanco(IServiceProvider serviceProvider)
{
using (var serviceScope = serviceProvider.CreateScope())
{
var context = serviceScope.ServiceProvider.GetService();
if (context.Database.EnsureCreated())
{
context.Blogs.Add(new Blog { Author = "Rafael Almeida", Url = "https://blog.ralms.net/" });
context.Blogs.Add(new Blog { Author = "Microsoft", Url = "https://blogs.msdn.microsoft.com/" });
context.Blogs.Add(new Blog { Author = "Asp Net Core", Url = "https://microsoft.com/net" });
context.SaveChanges();
}
}
}
private static async Task SimularRequisicaosAsync(IServiceProvider serviceProvider, Stopwatch stopSatch)
{
while (stopSatch.IsRunning)
{
using (var serviceScope = serviceProvider.CreateScope())
{
await new BlogController(serviceScope.ServiceProvider.GetService()).ActionAsync();
}
Interlocked.Increment(ref _requisicoesProcessadas);
}
}
private static async void Resultados(TimeSpan duracao, Stopwatch stopWatch)
{
var ultimaInstancia = 0L;
var ultimaRequisicao = 0L;
var ultimoTempo = TimeSpan.Zero;
stopWatch.Start();
while (stopWatch.Elapsed < duracao)
{
await Task.Delay(TimeSpan.FromSeconds(1));
var contadorInstancia = BlogContext.ContadorInstancia;
var contadorRequisicao = _requisicoesProcessadas;
var tempoCorrido = stopWatch.Elapsed;
var tempoAtual = tempoCorrido - ultimoTempo;
var requisicoes = contadorRequisicao - ultimaRequisicao;
Console.WriteLine(
$"{DateTime.Now:HH:mm:ss.fff} - "
+ $"Criação do DbContext/Segundo: {contadorInstancia - ultimaInstancia} | "
+ $"Requisição/Segundo: {Math.Round(requisicoes / tempoAtual.TotalSeconds)}");
ultimaInstancia = contadorInstancia;
ultimaRequisicao = contadorRequisicao;
ultimoTempo = tempoCorrido;
}
Console.WriteLine();
Console.WriteLine($"Total de Instancias Criadas......: {BlogContext.ContadorInstancia}");
Console.WriteLine(
$"Média de Requisições por Segundos: {Math.Round(_requisicoesProcessadas / stopWatch.Elapsed.TotalSeconds)}");
stopWatch.Stop();
}
}
public class Blog
{
public int Id { get; set; }
public string Author { get; set; }
public string Url { get; set; }
}
public class BlogContext : DbContext
{
public static long ContadorInstancia;
public BlogContext(DbContextOptions options)
: base(options)
{
Interlocked.Increment(ref ContadorInstancia);
}
public DbSet Blogs { get; set; }
}
public class BlogController
{
private readonly BlogContext _contextBlog;
public BlogController(BlogContext context)
{
_contextBlog = context;
}
public async Task ActionAsync()
{
await _contextBlog.Blogs.FirstAsync();
}
}
}
Ao executar nosso projeto teremos algo parecido com este, é óbvio que a cada execução poderemos ter valores diferentes, mais o foco aqui será mostrar a diferença entre usar o AddDbContext e o AddDbContextPool.
Em meu teste inicial eu obtive o seguinte resultado.
https://blog.ralms.net/imagens/techwiki/05.PNG
Se observarmos direito, ele criou milhares de instancias, isso pode afetar a performance de nossa aplicação.
agora iremos trocar apenas a API AddDbContext Para AddDbContextPool. E vamos rodar novamente a aplicação.
Observe agora o número significativo de instancias que foram reduzidas para apenas 50.
https://blog.ralms.net/imagens/techwiki/06.PNG
Pessoal por hoje é só, nosso intuito aqui foi mostrar como um todo .Net Core está evoluindo.
Cada dia que passa a ferramenta fica fantástica.