首页 > 编程语言 >c# .Net 对象池

c# .Net 对象池

时间:2024-06-17 15:31:55浏览次数:22  
标签:stopwatch c# 对象 var new Net public pool

对象池就是对象的容器,旨在优化资源的使用,通过在一个容器中池化对象,并根据需要重复使用这些池化对象来满足性能上的需求。当一个对象被激活时,便被从池中取出。当对象被停用时,它又被放回池中,等待下一个请求。

对象池一般用于对象的初始化过程代价较大或使用频率较高的场景。

在 ASP.NET Core 框架里(或者.net Framework高版本)已经内置了一个对象池功能的实现:Microsoft.Extensions.ObjectPool

池的策略与基本使用

首先,要使用 ObjectPool,需要创建一个池化策略,告诉对象池你将如何创建对象,以及如何归还对象。

该策略通过实现接口 IPooledObjectPolicy 来定义,下面是一个最简单的策略实现:

public class DefaultPooledObjectPolicy<T> : PooledObjectPolicy<T> where T : class, new()
{
    /// <inheritdoc />
    public override T Create()
    {
        return new T();
    }

    /// <inheritdoc />
    public override bool Return(T obj)
    {
        if (obj is IResettable resettable)
        {
            return resettable.TryReset();
        }

        return true;
    }
}

当对象池中没有实例时,则创建实例并返回给调用组件;当对象池中已有实例时,则直接取一个现有实例返回给调用组件。而且这个过程是线程安全的。

Microsoft.Extensions.ObjectPool 提供了默认的对象池实现:DefaultObjectPool<T>,它提供了借 Get 和还 Return 操作接口。创建对象池时需要提供池化策略 IPooledObjectPolicy<T> 作为其构造参数。

下面是一个默认对象池的基本使用

public class AutoMan
{
    public int Id { get; set; }
    public DateTime CreateTime { get; set; }
    public AutoMan()
    {
        Thread.Sleep(5000);//模拟对象耗时创建
        Id = new Random().Next();
        CreateTime = DateTime.Now;
    }
}
var policy = new DefaultPooledObjectPolicy<AutoMan>();
var pool = new DefaultObjectPool<AutoMan>(policy);
Stopwatch stopwatch = Stopwatch.StartNew();
for (int i = 0; i < 10; i++)
{
    var m = pool.Get();
    Console.WriteLine(i + "创建成功" + "id:" + m.Id + "用时:" + stopwatch.ElapsedMilliseconds);
    stopwatch.Restart();
    if (i >= 2)//前三个不归还到对象池
    {
        pool.Return(m);
    }
}

运行结果如图:

调用组件从对象池中借走一个对象实例,使用完后应立即归还给对象池,以便重复使用,避免因构造新对象消耗过多资源。

另外,还可以在DefaultObjectPool构造函数中指定对象池的容量。

总结

对象池的使用原则是:有借有还,再借不难。当调用组件从对象池中借走一个对象实例,使用完后应立即归还给对象池,以便重复利用,避免因过多的对象初始化影响系统性能。

对象池主要用在对象初始化比较耗时和使用比较频繁的场景,比如初始化时要读取网络资源,有时候这些对象因为有时效性,又不能用单例(后面会通过自定义策略来说明)。所以说,IOC并不能完全替代对象池。

以上知识来自于:.NET Core 对象池的使用 - 精致码农 - 博客园 (cnblogs.com)

对象池的预热和对象池大小的控制

像缓存一样,为了提高性能,我们可以在系统初始化的时候进行预热。

static void MaxPoolCount()
{
    var poolObjCount = 10;
    var policy = new DefaultPooledObjectPolicy<AutoMan>();
    var pool = new DefaultObjectPool<AutoMan>(policy, poolObjCount);//对象池容量为10

    List<AutoMan> list = new List<AutoMan>();
    Console.WriteLine("开始-----------------------------------");
    for (int i = 0; i < poolObjCount; i++)
    {
        var m = pool.Get();
        Console.WriteLine("增加一个对象池对象");
        list.Add(m);
    }
    foreach (AutoMan m in list)
    {
        pool.Return(m);
    }
    Console.WriteLine("预热结束-----------------------------------");
    List<Task> tasks = new List<Task>();
    var getCount = 20;
    for (int i = 0; i < getCount; i++)
    {
        tasks.Add(Task.Run(() =>
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            var m = pool.Get();
            stopwatch.Stop();
            Console.WriteLine("线程id:" + Thread.CurrentThread.ManagedThreadId + "创建成功,用时:" + stopwatch.ElapsedMilliseconds);
        }));
    }
    Task.WaitAll(tasks.ToArray());
}

运行结果:

 通过上述运行结果可以得知:并发请求数超过了对象池数量会导致重新创建对象。

自定义池策略

通过自定义池策略,可以加深对象池的理解,并可以清晰认识到他跟IOC使用场景的区别。

/// <summary>
/// 自定义对象池策略
/// </summary>
/// <typeparam name="T"></typeparam>
public class CustomPooledObjectPolicy : DefaultPooledObjectPolicy<AutoMan>
{
    public override AutoMan Create()
    {
        return base.Create();
    }
    public override bool Return(AutoMan obj)
    {
        if (obj == null) { return false; }
        //对象30秒过期
        if (obj.CreateTime.AddSeconds(30) < DateTime.Now)
        {
            return false;
        }
        return base.Return(obj);
    }
}
static void CustomPolicy()
{
    var poolObjCount = 10;
    var policy = new CustomPooledObjectPolicy();
    var pool = new DefaultObjectPool<AutoMan>(policy, poolObjCount);

    List<AutoMan> list = new List<AutoMan>();
    for (int i = 0; i < poolObjCount; i++)
    {
        var m = pool.Get();
        Console.WriteLine("增加一个对象池对象");
        list.Add(m);
    }
    //等待40秒,使得归还失败
    Thread.Sleep(40000);
    foreach (AutoMan m in list)
    {
        pool.Return(m);
    }
    Console.WriteLine("预热结束-----------------------------------");
    List<Task> tasks = new List<Task>();
    for (int i = 0; i < 5; i++)
    {
        tasks.Add(Task.Run(() =>
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            var m = pool.Get();
            stopwatch.Stop();
            Console.WriteLine("线程id:" + Thread.CurrentThread.ManagedThreadId + "创建成功,用时:" + stopwatch.ElapsedMilliseconds);
        }));
    }
    Task.WaitAll(tasks.ToArray());

}

 个人理解:如果不需要自定义策略,那使用IOC的单例跟这个对象池是没有区别的。但是需要自定义对象的创建和回收策略,那需要使用对象池

标签:stopwatch,c#,对象,var,new,Net,public,pool
From: https://www.cnblogs.com/chenxizhaolu/p/18252502

相关文章

  • 4种CSS实现全屏背景图片铺满自适应的方式,最后一种尤其简单
    在Web设计中,背景图片是提升页面视觉效果的重要元素。实现背景图片全屏铺满且自适应是常见的需求。本文将介绍三种CSS技术,用以确保背景图片能够优雅地填充整个屏幕并适应不同设备。方式一:使用background-size属性CSS的background-size属性可以设置背景图片的尺寸,使其覆盖整个......
  • cloud_enum:一款针对不同平台云环境安全的OSINT工具
    关于cloud_enumcloud_enum是一款功能强大的云环境安全OSINT工具,该工具支持AWS、Azure和GoogleCloud三种不同的云环境,旨在帮助广大研究人员枚举目标云环境中的公共资源,并尝试寻找其中潜在的安全威胁。功能介绍当前版本的cloud_enum支持枚举下列内容:AmazonWebServices......
  • 深入解读Netty中的NIO:原理、架构与实现详解
    深入解读Netty中的NIO:原理、架构与实现详解Netty是一个基于Java的异步事件驱动网络应用框架,广泛用于构建高性能、高可扩展性的网络服务器和客户端。Netty的核心是基于JavaNIO(Non-blockingI/O)的,因此理解Netty的实现需要先了解JavaNIO的基本概念和机制。JavaNIO简介Jav......
  • 深入浅出Netty:高性能网络应用框架的原理与实践
    深入浅出Netty:高性能网络应用框架的原理与实践1.Netty简介Netty是一个基于Java的异步事件驱动的网络应用框架,广泛用于构建高性能、高可扩展性的网络服务器和客户端。它提供对多种协议(如TCP、UDP、SSL等)的支持,适用于各种网络通信场景。2.核心组件Channel:代表一个到远程......
  • 医用压缩雾化器pcba方案
    雾化器是一种将药物液体转化为微小颗粒状物质并通过呼吸道输送到呼吸系统的医疗器械。常用于治疗呼吸道疾病,如哮喘、气管炎、肺炎、鼻窦炎等。且被广泛应用于医疗、美容、家居等领域。现代化的雾化器通常采用单片机方案控制,能够更加稳定地实现精准控制和多种功能。本文将介绍......
  • Win11系统提示找不到clretwrc.dll文件的解决办法
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个clretwrc.dll文件(挑选合适的版本文件)把它......
  • Win11系统提示找不到coadmin.dll文件的解决办法
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个coadmin.dll文件(挑选合适的版本文件)把它放......
  • Win11系统提示找不到commig.dll文件的解决办法
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个commig.dll文件(挑选合适的版本文件)把它放......
  • 华为OD机试C卷(100分)-绘图机器(C语言)
    题目描述绘图机器的绘图笔初始位置在原点(0,0)机器启动后按照以下规则来进行绘制直线。尝试沿着横线坐标正向绘制直线直到给定的终点E期间可以通过指令在纵坐标轴方向进行偏移,offsetY为正数表示正向偏移,为负数表示负向偏移给定的横坐标终点值E以及若干条绘制指令,......
  • Win11系统提示找不到coloradapterclient.dll文件的解决办法
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个coloradapterclient.dll文件(挑选合适的版本......