Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Por Günther Foidl, Steve Gordone Samson Amaugo
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.
Advertência
Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 10 deste artigo.
Microsoft.Extensions.ObjectPool faz parte da infraestrutura ASP.NET Core que suporta manter um grupo de objetos na memória para reutilização, em vez de permitir que os objetos sejam coletados como lixo. Todos os métodos estáticos e de instância em Microsoft.Extensions.ObjectPool são thread-safe.
Os aplicativos podem querer usar o pool de objetos se os objetos que estão sendo gerenciados forem:
- Caro para alocar/inicializar.
- Representam um recurso limitado.
- Usado de forma previsível e frequente.
Por exemplo, o framework ASP.NET Core utiliza o pool de objetos em algumas partes para reutilizar instâncias StringBuilder.
StringBuilder aloca e gerencia seus próprios buffers para armazenar dados de caracteres. ASP.NET Core usa regularmente StringBuilder para implementar recursos, e reutilizá-los oferece um benefício de desempenho.
O pool de objetos nem sempre melhora o desempenho:
- A menos que o custo de inicialização de um objeto seja alto, geralmente é mais lento obter o objeto do pool.
- Os objetos gerenciados pelo pool não são desalocados até que o pool seja desalocado.
Use o pool de objetos somente depois de coletar dados de desempenho usando cenários realistas para seu aplicativo ou biblioteca.
NOTA: O ObjectPool não coloca um limite no número de objetos que aloca, ele coloca um limite no número de objetos que retém.
Conceitos de ObjectPool
Quando DefaultObjectPoolProvider é usado e T implementa IDisposable:
- Os itens que não são devolvidos à piscina serão descartados.
- Quando a piscina é descartada pela DI, todos os itens da piscina são descartados.
NOTA: Depois de a piscina ser descartada:
- Chamar
Getgera umObjectDisposedException. - Chamar
Returnelimina o item fornecido.
Tipos de ObjectPool e interfaces importantes:
- ObjectPool<T> : A abstração básica do pool de objetos. Usado para obter e devolver objetos.
- PooledObjectPolicy<T> : Implemente isso para personalizar como um objeto é criado e como ele é redefinido quando retornado ao pool. Isso pode ser passado para um pool de objetos que é construído diretamente.
- IResettable : Redefine automaticamente o objeto quando retornado a um pool de objetos.
O ObjectPool pode ser usado em um aplicativo de várias maneiras:
- Instanciando um pool.
- Registrando um pool no de injeção de dependência (DI) como uma instância.
- Registar o
ObjectPoolProvider<>no DI e utilizá-lo como recurso.
Como usar o ObjectPool
Chame Get para obter um objeto e Return para retornar o objeto. Não há necessidade de devolver todos os objetos. Se um objeto não for devolvido, será recolhido lixo.
Exemplo de ObjectPool
O seguinte código:
- Adiciona
ObjectPoolProviderao contêiner de de injeção de dependência (DI) do. - Implementa a interface
IResettablepara limpar automaticamente o conteúdo do buffer quando retornado ao pool de objetos.
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.ObjectPool;
using System.Security.Cryptography;
var builder = WebApplication.CreateBuilder(args);
builder.Services.TryAddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
builder.Services.TryAddSingleton<ObjectPool<ReusableBuffer>>(serviceProvider =>
{
var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
var policy = new DefaultPooledObjectPolicy<ReusableBuffer>();
return provider.Create(policy);
});
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
// return the SHA256 hash of a word
// https://localhost:7214/hash/SamsonAmaugo
app.MapGet("/hash/{name}", (string name, ObjectPool<ReusableBuffer> bufferPool) =>
{
var buffer = bufferPool.Get();
try
{
// Set the buffer data to the ASCII values of a word
for (var i = 0; i < name.Length; i++)
{
buffer.Data[i] = (byte)name[i];
}
Span<byte> hash = stackalloc byte[32];
SHA256.HashData(buffer.Data.AsSpan(0, name.Length), hash);
return "Hash: " + Convert.ToHexString(hash);
}
finally
{
// Data is automatically reset because this type implemented IResettable
bufferPool.Return(buffer);
}
});
app.Run();
public class ReusableBuffer : IResettable
{
public byte[] Data { get; } = new byte[1024 * 1024]; // 1 MB
public bool TryReset()
{
Array.Clear(Data);
return true;
}
}
NOTA: Quando o tipo agrupado T não implementa IResettable, então um PooledObjectPolicy<T> personalizado pode ser usado para redefinir o estado dos objetos antes que eles sejam retornados ao pool.
Microsoft.Extensions.ObjectPool faz parte da infraestrutura ASP.NET Core que suporta manter um grupo de objetos na memória para reutilização, em vez de permitir que os objetos sejam coletados como lixo. Todos os métodos estáticos e de instância em Microsoft.Extensions.ObjectPool são thread-safe.
Os aplicativos podem querer usar o pool de objetos se os objetos que estão sendo gerenciados forem:
- Caro para alocar/inicializar.
- Representam um recurso limitado.
- Usado de forma previsível e frequente.
Por exemplo, o framework ASP.NET Core utiliza o pool de objetos em algumas partes para reutilizar instâncias StringBuilder.
StringBuilder aloca e gerencia seus próprios buffers para armazenar dados de caracteres. ASP.NET Core usa regularmente StringBuilder para implementar recursos, e reutilizá-los oferece um benefício de desempenho.
O pool de objetos nem sempre melhora o desempenho:
- A menos que o custo de inicialização de um objeto seja alto, geralmente é mais lento obter o objeto do pool.
- Os objetos gerenciados pelo pool não são desalocados até que o pool seja desalocado.
Use o pool de objetos somente depois de coletar dados de desempenho usando cenários realistas para seu aplicativo ou biblioteca.
NOTA: O ObjectPool não coloca um limite no número de objetos que aloca, ele coloca um limite no número de objetos que retém.
Conceitos
Quando DefaultObjectPoolProvider é usado e T implementa IDisposable:
- Os itens que não são devolvidos à piscina serão descartados.
- Quando a piscina é descartada pela DI, todos os itens da piscina são descartados.
NOTA: Depois de a piscina ser descartada:
- Chamar
Getgera umObjectDisposedException. - Chamar
Returnelimina o item fornecido.
Tipos de ObjectPool e interfaces importantes:
- ObjectPool<T> : A abstração básica do pool de objetos. Usado para obter e devolver objetos.
- PooledObjectPolicy<T> : Implemente isso para personalizar como um objeto é criado e como ele é redefinido quando retornado ao pool. Isso pode ser passado para um pool de objetos que é construído diretamente, ou
- Create : Atua como uma fábrica para criar conjuntos de objetos.
- IResettable: Redefine automaticamente o objeto quando retornado a um pool de objetos.
O ObjectPool pode ser usado em um aplicativo de várias maneiras:
- Instanciando um pool.
- Registrando um pool no de injeção de dependência (DI) como uma instância.
- Registar o
ObjectPoolProvider<>no DI e utilizá-lo como recurso.
Como usar o ObjectPool
Chame Get para obter um objeto e Return para retornar o objeto. Não há exigência de que você devolva todos os objetos. Se você não devolver um objeto, ele será coletado como lixo.
Exemplo de ObjectPool
O seguinte código:
- Adiciona
ObjectPoolProviderao contêiner de de injeção de dependência (DI) do. - Adiciona e configura
ObjectPool<StringBuilder>ao contêiner DI. - Adiciona o símbolo
BirthdayMiddleware.
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.ObjectPool;
using ObjectPoolSample;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.TryAddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
builder.Services.TryAddSingleton<ObjectPool<StringBuilder>>(serviceProvider =>
{
var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
var policy = new Microsoft.Extensions.ObjectPool.StringBuilderPooledObjectPolicy();
return provider.Create(policy);
});
builder.Services.AddWebEncoders();
var app = builder.Build();
// Test using /?firstname=Steve&lastName=Gordon&day=28&month=9
app.UseMiddleware<BirthdayMiddleware>();
app.MapGet("/", () => "Hello World!");
app.Run();
O código a seguir implementa BirthdayMiddleware
using System.Text;
using System.Text.Encodings.Web;
using Microsoft.Extensions.ObjectPool;
namespace ObjectPoolSample;
public class BirthdayMiddleware
{
private readonly RequestDelegate _next;
public BirthdayMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context,
ObjectPool<StringBuilder> builderPool)
{
if (context.Request.Query.TryGetValue("firstName", out var firstName) &&
context.Request.Query.TryGetValue("lastName", out var lastName) &&
context.Request.Query.TryGetValue("month", out var month) &&
context.Request.Query.TryGetValue("day", out var day) &&
int.TryParse(month, out var monthOfYear) &&
int.TryParse(day, out var dayOfMonth))
{
var now = DateTime.UtcNow; // Ignoring timezones.
// Request a StringBuilder from the pool.
var stringBuilder = builderPool.Get();
try
{
stringBuilder.Append("Hi ")
.Append(firstName).Append(" ").Append(lastName).Append(". ");
var encoder = context.RequestServices.GetRequiredService<HtmlEncoder>();
if (now.Day == dayOfMonth && now.Month == monthOfYear)
{
stringBuilder.Append("Happy birthday!!!");
var html = encoder.Encode(stringBuilder.ToString());
await context.Response.WriteAsync(html);
}
else
{
var thisYearsBirthday = new DateTime(now.Year, monthOfYear,
dayOfMonth);
int daysUntilBirthday = thisYearsBirthday > now
? (thisYearsBirthday - now).Days
: (thisYearsBirthday.AddYears(1) - now).Days;
stringBuilder.Append("There are ")
.Append(daysUntilBirthday).Append(" days until your birthday!");
var html = encoder.Encode(stringBuilder.ToString());
await context.Response.WriteAsync(html);
}
}
finally // Ensure this runs even if the main code throws.
{
// Return the StringBuilder to the pool.
builderPool.Return(stringBuilder);
}
return;
}
await _next(context);
}
}
Microsoft.Extensions.ObjectPool faz parte da infraestrutura ASP.NET Core que suporta manter um grupo de objetos na memória para reutilização, em vez de permitir que os objetos sejam coletados como lixo.
Talvez você queira usar o pool de objetos se os objetos que estão sendo gerenciados forem:
- Caro para alocar/inicializar.
- Representam um recurso limitado.
- Usado de forma previsível e frequente.
Por exemplo, o framework ASP.NET Core utiliza o pool de objetos em algumas partes para reutilizar instâncias StringBuilder.
StringBuilder aloca e gerencia seus próprios buffers para armazenar dados de caracteres. ASP.NET Core usa regularmente StringBuilder para implementar recursos, e reutilizá-los oferece um benefício de desempenho.
O pool de objetos nem sempre melhora o desempenho:
- A menos que o custo de inicialização de um objeto seja alto, geralmente é mais lento obter o objeto do pool.
- Os objetos gerenciados pelo pool não são desalocados até que o pool seja desalocado.
Use o pool de objetos somente depois de coletar dados de desempenho usando cenários realistas para seu aplicativo ou biblioteca.
AVISO: O ObjectPool não implementa IDisposable. Não recomendamos usá-lo com materiais que precisam ser descartados.
ObjectPool no ASP.NET Core 3.0 ou posterior suporta IDisposable.
NOTA: O ObjectPool não coloca um limite no número de objetos que irá alocar, coloca um limite no número de objetos que irá reter.
Conceitos
ObjectPool<T> - a abstração básica do pool de objetos. Usado para obter e devolver objetos.
PooledObjectPolicy<T> - implemente isso para personalizar como um objeto é criado e como ele é redefinido quando retornado ao pool. Isso pode ser passado para um pool de objetos que você constrói diretamente.... OU
Create atua como uma fábrica para a criação de pools de objetos.
O ObjectPool pode ser usado em um aplicativo de várias maneiras:
- Instanciando um pool.
- Registrando um pool no de injeção de dependência (DI) como uma instância.
- Registar o
ObjectPoolProvider<>no DI e utilizá-lo como recurso.
Como usar o ObjectPool
Chame Get para obter um objeto e Return para retornar o objeto. Não há exigência de que você devolva todos os objetos. Se você não devolver um objeto, ele será coletado como lixo.
Exemplo de ObjectPool
O seguinte código:
- Adiciona
ObjectPoolProviderao contêiner de de injeção de dependência (DI) do. - Adiciona e configura
ObjectPool<StringBuilder>ao contêiner DI. - Adiciona o símbolo
BirthdayMiddleware.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
services.TryAddSingleton<ObjectPool<StringBuilder>>(serviceProvider =>
{
var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
var policy = new StringBuilderPooledObjectPolicy();
return provider.Create(policy);
});
services.AddWebEncoders();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Test using /?firstname=Steve&lastName=Gordon&day=28&month=9
app.UseMiddleware<BirthdayMiddleware>();
}
}
O código a seguir implementa BirthdayMiddleware
public class BirthdayMiddleware
{
private readonly RequestDelegate _next;
public BirthdayMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context,
ObjectPool<StringBuilder> builderPool)
{
if (context.Request.Query.TryGetValue("firstName", out var firstName) &&
context.Request.Query.TryGetValue("lastName", out var lastName) &&
context.Request.Query.TryGetValue("month", out var month) &&
context.Request.Query.TryGetValue("day", out var day) &&
int.TryParse(month, out var monthOfYear) &&
int.TryParse(day, out var dayOfMonth))
{
var now = DateTime.UtcNow; // Ignoring timezones.
// Request a StringBuilder from the pool.
var stringBuilder = builderPool.Get();
try
{
stringBuilder.Append("Hi ")
.Append(firstName).Append(" ").Append(lastName).Append(". ");
var encoder = context.RequestServices.GetRequiredService<HtmlEncoder>();
if (now.Day == dayOfMonth && now.Month == monthOfYear)
{
stringBuilder.Append("Happy birthday!!!");
var html = encoder.Encode(stringBuilder.ToString());
await context.Response.WriteAsync(html);
}
else
{
var thisYearsBirthday = new DateTime(now.Year, monthOfYear,
dayOfMonth);
int daysUntilBirthday = thisYearsBirthday > now
? (thisYearsBirthday - now).Days
: (thisYearsBirthday.AddYears(1) - now).Days;
stringBuilder.Append("There are ")
.Append(daysUntilBirthday).Append(" days until your birthday!");
var html = encoder.Encode(stringBuilder.ToString());
await context.Response.WriteAsync(html);
}
}
finally // Ensure this runs even if the main code throws.
{
// Return the StringBuilder to the pool.
builderPool.Return(stringBuilder);
}
return;
}
await _next(context);
}
}