写点什么

.NET CORE 对象池简述

用户头像
喵叔
关注
发布于: 4 小时前

一、什么是对象池

在 .NET 中有各种池子,例如数据库连接池和线程池,今天我们要说的这个池子是对象池。他是对象的容器,通过在容器中池化对象,根据需要重复使用这些出花对象来解决性能上的问题,以及解决性能上的需求。使用对象池简单的描述是:当需要一个对象是就从对象池中取出来,用完之后再放回去等待下一次使用。使用对象池的场景一般会在对象的使用频率很高,频繁创建对象会有性能问题的情况下,以及对象的初始化过程代价很大的情况下使用。

二、策略

以.net core 控制台为例,我们来看一下池化策略怎么定义。首先我们需要在项目中安装 Microsoft.Extensions.ObjectPool 扩展库。接着利用 ObjectPool 创建一个池化策略,来告诉对象池创建对象的方法和归还对象的方法。我们通常会使用 IPooledObjectPolicy 接口来定义池化策略。实现如下:

using Microsoft.Extensions.ObjectPool;
namespace OP
{
public class OPPooledObject:IPooledObjectPolicy<Student>
{
public Student Create()
{
return new Student();
}
public bool Return(Student obj)
{
return true;
}
}
public class Student
{
public string name { get; set; }
public string address { get; set; }
}
}
复制代码

上面的代码只是为了展示如何定义池化策略而编写的,在实际的开发中如果不需要定义复杂的逻辑结构,可以使用默认的 DefaultPooledObjectPolicy<T> 泛型来实现。

三、使用

上面我们已经定义好了池化策略,有了策略下面我们就来看一下对象池的使用。对象池的使用很简单,只需要记住有借有还这四个字即可。在使用时如果对象池中没有实例时,就会创建实例并返回给调用方,如果存在实例就直接将实例返回给调用方。这个过程是线程安全的。同样,我们在控制台中调用前面我们编写的策略来创建对象。

using Microsoft.Extensions.ObjectPool;
using System;
namespace OP
{
class Program
{
static void Main(string[] args)
{
var opo = new OPPooledObject();
var dop = new DefaultObjectPool<Student>(opo);
var student1 = dop.Get();
//打印student1
Console.WriteLine("student1:" + student1.id);
//归还student1
dop.Return(student1);
var student2 = dop.Get();
//打印student2
Console.WriteLine("student2:" + student2.id);
//归还student2
dop.Return(student2);
Console.ReadLine();
}
}
}
复制代码

运行上面的代码将得到如下结果:


通过 id 我们可以看出,student1 和 student2 是同一个对象。如果我们只将对象 Get 出来,但是不执行 Return 方法会怎么样呢?


我们可以看出来 student1 和 studen2 的 id 不一样了,说明了这是两个对象。因此,我们在使用对象池的时候要记得在使用完对象一定要调用 Return 方法归还对象,这样才能重复使用,避免因构造新对象对资源的消耗过多。在上面的代码中我们使用了一个默认的一个对象池 DefaultObjectPool<T> ,它提供了 Get 和 Return 操作接口。在创建对象池时需要提供继承了 IPooledObjectPolicy<T>  接口的池化策略作为构造参数。

四、限制对象池大小

我们在使用 DefaultObjectPool<T> 创建对象池的时候可以给它传入一个数字来指定对象池大小,它是用来指定最大可以从对象池中取出的对象数量,当取出的对象数量超过该数值后,超出的对象将不会被池化。下面我们通过一个例子来看一下。

using Microsoft.Extensions.ObjectPool;
using System;
namespace OP
{
class Program
{
static void Main(string[] args)
{
var opo = new OPPooledObject();
var dop = new DefaultObjectPool<Student>(opo,2);
var student1 = dop.Get();
//打印student1
Console.WriteLine("student1:" + student1.id);
var student2 = dop.Get();
//打印student2
Console.WriteLine("student2:" + student2.id);
var student3 = dop.Get();
//打印student3
Console.WriteLine("student3:" + student3.id);
//归还student1
dop.Return(student1);
//归还student2
dop.Return(student2);
//归还student3
dop.Return(student3);
var student4 = dop.Get();
//打印student4
Console.WriteLine("student4:" + student4.id);
var student5= dop.Get();
//打印student5
Console.WriteLine("student5:" + student5.id);
var student6 = dop.Get();
//打印student6
Console.WriteLine("student6:" + student6.id);
//归还student4
dop.Return(student4);
//归还student5
dop.Return(student5);
//归还student6
dop.Return(student6);
Console.ReadLine();
}
}
}
复制代码


运行上面的代码得到如下结果:


从输出结果中我们可以看出,studen1 和 student4、student2 和 student 5 的 id 值是一样的,student3 和 student6 的 id 值是不一样的。虽然我们第一次和第二次从对象池中分别 Get 出了三个对象,并且都进行了 Return ,但是因为我们指定的对象池容量大小是 2 个对象,无法容下点个对象,因此第三个对象是无法被池化的。

五、结束

到这里 .NET CORE 中的对象池的基本内容已经讲解完毕,这里所有的代码都是运行在 .NET CORE 控制台中的,对于 ASP.NET CORE 中使用对象池的内容,微软的官方文档已经很清楚了,这里就不进行阐述了。总的来说 Microsoft.Extensions.ObjectPool 所提供的对象池比较灵活的。一般场景使用默认的池化策略、默认的对象池以及默认的对象池提供者就可以满足需求,在特殊的情况下或者需求比较复杂的情况下也可以自定义其中任意某部件来实现。

发布于: 4 小时前阅读数: 3
用户头像

喵叔

关注

还未添加个人签名 2020.01.14 加入

还未添加个人简介

评论

发布
暂无评论
.NET CORE 对象池简述