通过Steve Gordon, Ryan Nowak,和Rick Anderson
Microsoft.Extensions.ObjectPool 是支持将一组对象保存在内存中以供重复使用,而不允许的对象进行垃圾收集的 ASP.NET Core 基础结构的一部分。
您可能想要使用对象池,如果正在管理的对象:
例如,ASP.NET Core 框架将使用对象池在某些位置重复使用StringBuilder实例。 StringBuilder
分配和管理其自己的缓冲区来存放字符数据。 ASP.NET Core 定期使用StringBuilder
为了实现功能,并重复使用它们提供性能优势。
对象池始终不会提高性能:
使用对象池仅在为应用或库使用实际的方案的性能数据收集后。
警告:ObjectPool
不会实现IDisposable
。我们不建议将用于需要可供使用的类型。
注意:ObjectPool 不置于将分配的对象数的限制,它将保留的对象数施加限制。
ObjectPool<T> -基本对象池抽象。 用于获取和返回对象。
PooledObjectPolicy<T> -实现此接口可以自定义如何创建对象以及如何重置时返回到池中。 这可以传递到直接构造的对象池...或
Create 充当用于创建对象池的工厂。
ObjectPool 可以采用多种方式应用:
ObjectPoolProvider<>
在 DI 并将其用作工厂。调用ObjectPool<T>来获取的对象和Return来返回的对象。 没有任何要求返回的每个对象。 如果不返回一个对象,它将进行垃圾回收。
下面的代码:
ObjectPoolProvider
到依赖关系注入(DI) 容器。ObjectPool<StringBuilder>
到 DI 容器。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); }); } 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>(); } }
下面的代码实现 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(". "); if (now.Day == dayOfMonth && now.Month == monthOfYear) { stringBuilder.Append("Happy birthday!!!"); await context.Response.WriteAsync(stringBuilder.ToString()); } 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!"); await context.Response.WriteAsync(stringBuilder.ToString()); } } finally // Ensure this runs even if the main code throws. { // Return the StringBuilder to the pool. builderPool.Return(stringBuilder); } return; } await _next(context); } }