ASP.NET Core 对象池化技术

写在前面

Microsoft.Extensions.ObjectPool 是 ASP.NET Core 基础结构的一部分,当对象的初始化成本较高,并且可能被频繁使用时,才适合采用对象池技术;被ObjectPool管理的对象不会进入垃圾回收,使用时通过由实例对象实现的Get()方法,从对象池中借出对象,用完之后调用Return(T obj)方法,将对象还回去。也可以在Return(T obj)方法中设置判断条件,仅允许特定的对象进入对象池。

通过NuGet 获取 Microsoft.Extensions.ObjectPool 类库

代码实现

using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.ObjectPool;
using System.Security.Cryptography;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// DefaultPooledObjectPolicy: 默认的策略,继承抽象类PooledObjectPolicy
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);
});

builder.Services.TryAddSingleton<ObjectPool<Person>>(serviceProvider => {
    var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
    var policy = new PersonPoolPolicy();
    return provider.Create(policy);
});

builder.Services.TryAddSingleton<ObjectPool<StringBuilder>>(serviceProvider =>
{
    var provider = serviceProvider.GetRequiredService<ObjectPoolProvider>();
    var policy = new StringBuilderPooledObjectPolicy();
    return provider.Create(policy);
});

var app = builder.Build();

// config middleware
app.UseMiddleware<BirthdayMiddleware>();

app.MapGet("/", () => "Hello rjcql!");

// return the SHA256 hash of a word 
http://localhost:5128/hash/xxxx
app.MapGet("/hash/{word}", (string word, ObjectPool<ReusableBuffer> bufferPool) =>
{

    var buffer = bufferPool.Get();
    try
    {
        // Set the buffer data to the ASCII values of a word
        for (var i = 0; i < word.Length; i++)
        {
            buffer.Data[i] = (byte)word[i];
        }

        Span<byte> hash = stackalloc byte[32];
        SHA256.HashData(buffer.Data.AsSpan(0, word.Length), hash);
        return "Hash: " + Convert.ToHexString(hash);
    }
    finally
    {
        // Data is automatically reset because this type implemented IResettable
        bufferPool.Return(buffer);
    }
});

app.MapGet("/create/{name}", (string name, ObjectPool<Person> personPool) =>
{
    var person = personPool.Get();
    try
    {
        person.Id = Guid.NewGuid().ToString("N");
        var lastName = person.Name; // 这个是上一个对象的值
        person.Name = name;
        return $"{person.Id}:{person.Name}, {lastName}";
    }
    finally
    {
        // 根据条件回收
        personPool.Return(person);
    }
});

app.Run();

public class ReusableBuffer : IResettable
{
    public byte[] Data { get; } = new byte[1024 * 1024]; // 1 MB

    public bool TryReset()
    {
        Array.Clear(Data);
        return true;
    }
}

public class Person
{
    public string Id { get; set; }

    public string Name { get; set; }
}

public class PersonPoolPolicy : PooledObjectPolicy<Person>
{
    public override Person Create()
    {
        return new Person { Id = "", Name = "rjcql" };
    }

    public override bool Return(Person p)
    {
        if (p.Name != "rjcql")
        {
            // 不允许其他名称的对象放入对象池
            return false;
        }
        return true;
    }
}

/// <summary>
/// 创建中间件
/// </summary>
public class BirthdayMiddleware
{
    private readonly RequestDelegate _next;

    public BirthdayMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, ObjectPool<StringBuilder> builderPool)
    {
        var stringBuilder = builderPool.Get();
        try
        {
            stringBuilder.Append("Hi");
            // 在中间干点啥别的
            // await context.Response.WriteAsync(stringBuilder.ToString());
            await _next.Invoke(context);
        }
        finally // 即使出错也要保证归还对象
        {
            builderPool.Return(stringBuilder);
        }
    }
}

调用示例

 

 

 

 因为设置了回收条件,所以只有名字为rjcql的对象才会被回收,所以每次调用都先把rjcql对象取出。

相关推荐

  1. 【Unity】对象技术

    2024-01-20 17:26:01       60 阅读
  2. GenericObjectPool对象的介绍与用法

    2024-01-20 17:26:01       23 阅读
  3. 22/76-

    2024-01-20 17:26:01       52 阅读
  4. Mybatis源码解析之——数据源技术(二)

    2024-01-20 17:26:01       44 阅读
  5. 深入理解RCNN:区域建议与区域兴趣技术解析

    2024-01-20 17:26:01       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-20 17:26:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-20 17:26:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-20 17:26:01       87 阅读
  4. Python语言-面向对象

    2024-01-20 17:26:01       96 阅读

热门阅读

  1. C++中的预处理

    2024-01-20 17:26:01       64 阅读
  2. 配置dns主从服务器,能够实现正常的正反向解析

    2024-01-20 17:26:01       56 阅读
  3. 2024.1.19

    2024-01-20 17:26:01       59 阅读
  4. [面试题~]Golang

    2024-01-20 17:26:01       53 阅读
  5. PMP专业术语

    2024-01-20 17:26:01       54 阅读
  6. 解决el-radio-group只触发一次的问题

    2024-01-20 17:26:01       57 阅读
  7. Ubuntu18.04 gcc找不到

    2024-01-20 17:26:01       61 阅读
  8. 开源软件合规风险与开源协议的法律效力

    2024-01-20 17:26:01       63 阅读
  9. Elasticsearch 中的 term、terms 和 match 查询

    2024-01-20 17:26:01       64 阅读