Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Di Günther Foidl, Steve Gordon e Samson Amaugo
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Microsoft.Extensions.ObjectPool fa parte dell'infrastruttura di ASP.NET Core che consente di mantenere un gruppo di oggetti in memoria per il riutilizzo invece di consentire la raccolta di oggetti inutilizzati. Tutti i metodi statici e di istanza in Microsoft.Extensions.ObjectPool sono sicuri per l'uso con i thread.
Le app potrebbero voler usare il pool di oggetti se gli oggetti gestiti sono:
- Costoso da allocare/inizializzare.
- Rappresenta una risorsa limitata.
- Usato in modo prevedibile e frequente.
Ad esempio, il framework ASP.NET Core utilizza il pool di oggetti in alcuni punti per riutilizzare le istanze StringBuilder.
StringBuilder alloca e gestisce i propri buffer per contenere i dati carattere. ASP.NET Core usa StringBuilder regolarmente per implementare le funzionalità e riutilizzarle offre un vantaggio per le prestazioni.
Il pool di oggetti non migliora sempre le prestazioni:
- A meno che il costo di inizializzazione di un oggetto non sia elevato, in genere è più lento ottenere l'oggetto dal pool.
- Gli oggetti gestiti dal pool non vengono deallocati fino a quando il pool non viene deallocato.
Usare il pool di oggetti solo dopo la raccolta di dati sulle prestazioni usando scenari realistici per l'app o la libreria.
NOTA: ObjectPool non inserisce un limite al numero di oggetti allocati, ma limita il numero di oggetti che mantiene.
Concetti relativi a ObjectPool
Quando DefaultObjectPoolProvider viene usato e T viene implementato IDisposable:
- Gli elementi non restituiti al pool verranno eliminati.
- Quando il pool viene smaltito dal Dependency Injection, tutti gli elementi nel pool vengono smaltiti.
NOTA: dopo lo smaltimento del pool:
- La chiamata
Getgenera un'eccezioneObjectDisposedException. - La chiamata
Returnelimina l'elemento specificato.
Tipi e interfacce importanti ObjectPool :
- ObjectPool<T> : L'astrazione di base del pool di oggetti. Utilizzato per ottenere e restituire oggetti.
- PooledObjectPolicy<T> : implementare questa opzione per personalizzare il modo in cui viene creato un oggetto e come viene reimpostato quando viene restituito al pool. Può essere passato a un pool di oggetti costruito direttamente.
- IResettable : reimposta automaticamente l'oggetto quando viene restituito a un pool di oggetti.
ObjectPool può essere usato in un'app in diversi modi:
- Creazione di un'istanza per un pool.
- Registrazione di un pool in inserimento delle dipendenze (DI) come istanza.
- Registrazione di
ObjectPoolProvider<>nell'inserimento delle dipendenze e utilizzo come factory.
Come usare ObjectPool
Chiamare Get per ottenere un oggetto e Return per restituire l'oggetto . Non è necessario restituire ogni oggetto. Se un oggetto non viene restituito, verrà raccolto dal Garbage Collector.
Esempio di ObjectPool
Il codice seguente:
- Aggiunge
ObjectPoolProvideral contenitore di Iniezione di Dipendenze (DI). - Implementa l'interfaccia
IResettableper cancellare automaticamente il contenuto del buffer quando viene restituito al pool di oggetti.
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 il tipo T in pool non implementa IResettable, è possibile usare un oggetto personalizzato PooledObjectPolicy<T> per reimpostare lo stato degli oggetti prima che vengano restituiti al pool.
Microsoft.Extensions.ObjectPool fa parte dell'infrastruttura di ASP.NET Core che consente di mantenere un gruppo di oggetti in memoria per il riutilizzo invece di consentire la raccolta di oggetti inutilizzati. Tutti i metodi statici e di istanza in Microsoft.Extensions.ObjectPool sono sicuri per l'uso con i thread.
Le app potrebbero voler usare il pool di oggetti se gli oggetti gestiti sono:
- Costoso da allocare/inizializzare.
- Rappresenta una risorsa limitata.
- Usato in modo prevedibile e frequente.
Ad esempio, il framework ASP.NET Core utilizza il pool di oggetti in alcuni punti per riutilizzare le istanze StringBuilder.
StringBuilder alloca e gestisce i propri buffer per contenere i dati carattere. ASP.NET Core usa StringBuilder regolarmente per implementare le funzionalità e riutilizzarle offre un vantaggio per le prestazioni.
Il pool di oggetti non migliora sempre le prestazioni:
- A meno che il costo di inizializzazione di un oggetto non sia elevato, in genere è più lento ottenere l'oggetto dal pool.
- Gli oggetti gestiti dal pool non vengono deallocati fino a quando il pool non viene deallocato.
Usare il pool di oggetti solo dopo la raccolta di dati sulle prestazioni usando scenari realistici per l'app o la libreria.
NOTA: ObjectPool non inserisce un limite al numero di oggetti allocati, ma limita il numero di oggetti che mantiene.
Concetti
Quando DefaultObjectPoolProvider viene usato e T viene implementato IDisposable:
- Gli elementi non restituiti al pool verranno eliminati.
- Quando il pool viene smaltito dal Dependency Injection, tutti gli elementi nel pool vengono smaltiti.
NOTA: dopo lo smaltimento del pool:
- La chiamata
Getgenera un'eccezioneObjectDisposedException. - La chiamata
Returnelimina l'elemento specificato.
Tipi e interfacce importanti ObjectPool :
- ObjectPool<T> : L'astrazione di base del pool di oggetti. Utilizzato per ottenere e restituire oggetti.
- PooledObjectPolicy<T> : implementare questa opzione per personalizzare il modo in cui viene creato un oggetto e come viene reimpostato quando viene restituito al pool. Questa può essere passata in un pool di oggetti che viene costruito direttamente oppure
- Create : funge da factory per la creazione di pool di oggetti.
- IResettable: reimposta automaticamente l'oggetto quando viene restituito a un pool di oggetti.
ObjectPool può essere usato in un'app in diversi modi:
- Creazione di un'istanza per un pool.
- Registrazione di un pool in inserimento delle dipendenze (DI) come istanza.
- Registrazione di
ObjectPoolProvider<>nell'inserimento delle dipendenze e utilizzo come factory.
Come usare ObjectPool
Chiamare Get per ottenere un oggetto e Return per restituire l'oggetto . Non è necessario che vengano restituiti tutti gli oggetti. Se non restituisci un oggetto, sarà sottoposto a raccolta dei rifiuti.
Esempio di ObjectPool
Il codice seguente:
- Aggiunge
ObjectPoolProvideral contenitore di Iniezione di Dipendenze (DI). - Aggiunge e configura il contenitore delle dipendenze
ObjectPool<StringBuilder>. - Aggiunge il
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();
Il codice seguente 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 fa parte dell'infrastruttura di ASP.NET Core che consente di mantenere un gruppo di oggetti in memoria per il riutilizzo invece di consentire la raccolta di oggetti inutilizzati.
È possibile usare il pool di oggetti se gli oggetti gestiti sono:
- Costoso da allocare/inizializzare.
- Rappresenta una risorsa limitata.
- Usato in modo prevedibile e frequente.
Ad esempio, il framework ASP.NET Core utilizza il pool di oggetti in alcuni punti per riutilizzare le istanze StringBuilder.
StringBuilder alloca e gestisce i propri buffer per contenere i dati carattere. ASP.NET Core usa StringBuilder regolarmente per implementare le funzionalità e riutilizzarle offre un vantaggio per le prestazioni.
Il pool di oggetti non migliora sempre le prestazioni:
- A meno che il costo di inizializzazione di un oggetto non sia elevato, in genere è più lento ottenere l'oggetto dal pool.
- Gli oggetti gestiti dal pool non vengono deallocati fino a quando il pool non viene deallocato.
Usare il pool di oggetti solo dopo la raccolta di dati sulle prestazioni usando scenari realistici per l'app o la libreria.
AVVISO: ObjectPool non implementa IDisposable. Non è consigliabile usarlo con i tipi che richiedono lo smaltimento.
ObjectPool in ASP.NET Core 3.0 o versione successiva supporta IDisposable.
NOTA: ObjectPool non inserisce un limite al numero di oggetti che alloca, ma limita il numero di oggetti che manterrà.
Concetti
ObjectPool<T> - l'astrazione di base del pool di oggetti. Utilizzato per ottenere e restituire oggetti.
PooledObjectPolicy<T> : implementare questa opzione per personalizzare la modalità di creazione di un oggetto e la modalità di reimpostazione quando viene restituito al pool. Questo può essere inserito in un pool di oggetti che costruisci direttamente.
Create funge da factory per la creazione di pool di oggetti.
ObjectPool può essere usato in un'app in diversi modi:
- Creazione di un'istanza per un pool.
- Registrazione di un pool in inserimento delle dipendenze (DI) come istanza.
- Registrazione di
ObjectPoolProvider<>nell'inserimento delle dipendenze e utilizzo come factory.
Come usare ObjectPool
Chiamare Get per ottenere un oggetto e Return per restituire l'oggetto . Non è necessario che vengano restituiti tutti gli oggetti. Se non restituisci un oggetto, sarà sottoposto a raccolta dei rifiuti.
Esempio di ObjectPool
Il codice seguente:
- Aggiunge
ObjectPoolProvideral contenitore di Iniezione di Dipendenze (DI). - Aggiunge e configura il contenitore delle dipendenze
ObjectPool<StringBuilder>. - Aggiunge il
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>();
}
}
Il codice seguente 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);
}
}