在 ASP.NET Core 中使用 ObjectPool 进行对象重用Object reuse with ObjectPool in ASP.NET Core

是 ASP.NET Core 基础结构的一部分,该基础结构支持在内存中保留一组对象以供重复使用,而不是允许对对象进行垃圾回收。

如果要管理的对象是,则你可能需要使用对象池:

  • 分配/初始化成本高昂。
  • 表示某些有限资源。
  • 使用可预测和频繁。

例如,ASP.NET Core 框架在某些位置使用对象池来重复使用 StringBuilder 实例。 分配并管理自己的用于保存字符数据的缓冲区。ASP.NET Core 会定期使用 StringBuilder 来实现功能,并重复使用这些功能以提高性能。

  • 除非对象的初始化开销较高,否则从池中获取该对象的速度通常较慢。
  • 在取消分配池之前,不会释放池管理的对象。

仅在使用应用或库的现实方案收集性能数据后,才使用对象池。

警告: ObjectPool 未实现 IDisposable。建议不要将其与需要处置的类型一起使用。

注意: ObjectPool 不会对它将分配的对象数量施加限制,它会限制将保留的对象数。

实现此方法,以便自定义对象的创建方式,以及如何在返回到池时重置对象。这可以传递到你直接构造的对象池中 .。。或

Create 充当创建对象池的工厂。

可以通过多种方式在应用中使用 ObjectPool:

  • 实例化池。
  • 在(DI)中将池注册为实例。
  • 在 DI 中注册 ObjectPoolProvider<>,并将其作为工厂使用。

调用 ObjectPool<T> 以获取对象并 返回对象。不要求你返回每个对象。如果不返回对象,将对其进行垃圾回收。

  • ObjectPoolProvider 添加到依赖关系注入(DI)容器中。
  • 向 DI 容器添加并配置 ObjectPool<StringBuilder>
  • 添加 BirthdayMiddleware

下面的代码实现 BirthdayMiddleware

  1. public class BirthdayMiddleware
  2. {
  3. private readonly RequestDelegate _next;
  4. public BirthdayMiddleware(RequestDelegate next)
  5. {
  6. _next = next;
  7. }
  8. public async Task InvokeAsync(HttpContext context,
  9. {
  10. if (context.Request.Query.TryGetValue("firstName", out var firstName) &&
  11. context.Request.Query.TryGetValue("lastName", out var lastName) &&
  12. context.Request.Query.TryGetValue("day", out var day) &&
  13. int.TryParse(month, out var monthOfYear) &&
  14. int.TryParse(day, out var dayOfMonth))
  15. {
  16. var now = DateTime.UtcNow; // Ignoring timezones.
  17. // Request a StringBuilder from the pool.
  18. var stringBuilder = builderPool.Get();
  19. try
  20. {
  21. stringBuilder.Append("Hi ")
  22. .Append(firstName).Append(" ").Append(lastName).Append(". ");
  23. if (now.Day == dayOfMonth && now.Month == monthOfYear)
  24. {
  25. stringBuilder.Append("Happy birthday!!!");
  26. await context.Response.WriteAsync(stringBuilder.ToString());
  27. }
  28. else
  29. dayOfMonth);
  30. int daysUntilBirthday = thisYearsBirthday > now
  31. ? (thisYearsBirthday - now).Days
  32. : (thisYearsBirthday.AddYears(1) - now).Days;
  33. stringBuilder.Append("There are ")
  34. .Append(daysUntilBirthday).Append(" days until your birthday!");
  35. await context.Response.WriteAsync(stringBuilder.ToString());
  36. }
  37. }
  38. finally // Ensure this runs even if the main code throws.
  39. {
  40. // Return the StringBuilder to the pool.
  41. builderPool.Return(stringBuilder);
  42. }
  43. return;
  44. }
  45. await _next(context);
  46. }