c# .Net 对象池

news/2024/10/2 22:24:19

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

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

在 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的单例跟这个对象池是没有区别的。但是需要自定义对象的创建和回收策略,那需要使用对象池

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/44738.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

VScode配置 Django项目 使用应用下的tests.py测试

文件目录tests.py import os import sys from pathlib import Path# Add base directory to PYTHONPATH if __name__ == "__main__":os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MyshopBack.settings")BASE_DIR = Path(__file__).resolve…

悬浮贴样式

悬浮贴样式 悬浮贴样式效果图如下:预览地址:https://www.cnblogs.com/leo130-blogs/p/18251987html语句: <div class="sticker" ><div class="sticker-title"></div><div class="sticker-detail"><div class="…

OpenCV + sklearnSVM 实现手写数字分割和识别

这学期机器学习考核方式以大作业的形式进行考核,而且只能使用一些传统的机器学习算法。 综合再三,选择了自己比较熟悉的MNIST数据集以及OpenCV来完成手写数字的分割和识别作为大作业。1. 数据集准备MNIST数据集是一个手写数字的数据库,包含60000张训练图片和10000张测试图片…

3.26随笔

SELECT DISTINCT 实例 下面的 SQL 语句仅从 "Websites" 表的 "country" 列中选取唯一不同的值,也就是去掉 "country" 列重复值:实例SELECT DISTINCT country FROM Websites;输出结果:

KVM虚拟化

KVM虚拟化 ============================================================= 0.环境介绍 宿主机:内存4G+ 纯净的系统CentOS-7 1:什么是虚拟化? 虚拟化,通过模拟计算机的硬件,来实现在同一台计算机上同时运行多个不同的操作系统的技术。2:为什么要用虚拟化? 2.1:虚拟化…

利用大模型服务一线小哥的探索与实践

一、小哥作业+大模型 2022年OpenAI基于GPT推出了聊天机器人ChatGPT,带来了非常惊艳的语言理解、内容生成、知识推理等能力,能够准确理解人的语言、意图,并能够回答出清晰、完整的内容,让人很难分辨出沟通交流的是人类还是机器人。 大模型会尝试基于已有的内容,生成内容的延…

腾讯云+Ollama部署远程访问大模型api

Ollama是个极为方便的大模型框架 1.腾讯云上选购合适的云服务器,为了方便拉取模型,地区建议选择北美(计费模式选择按量计费是为了省钱,老板有钱的话随意)架构选择异构计算镜像选择Ubuntu22.04,驱动版本默认就行,云硬盘默认50G即可网络默认分配即可,一定要选择分配独立公网IP,否…

3.21随笔

SELECT Column 实例 下面的 SQL 语句从 "Websites" 表中选取 "name" 和 "country" 列:实例SELECT name,country FROM Websites;输出结果为: