前言

对象池是一种设计模式,一个对象池包含一组已经初始化过且可以使用的对象,而可以在有需求时创建和销毁对象。池的对象可以从池中取得对象,对其进行操作处理,并在不需要时归还给池子而非直接销毁他,他是一种特殊的工厂对象。

若初始化、实例化的代价高,且有需求需要经常实例化,但每次实例化的数量较小的情况下,使用对象池可以过得显著的性能提升。从池子中取得对象的时间是可测的,但新建一个实际所需要的时间是不确定的。

对象池的优势

说到池我们就会联想到很多的概念,如线程池、数据库连接池、内存池等等在多线程设计中可以通过池化机制来进行对象的复用从而提高性能。池的核心优势是 对象复用,这样就免去了对象创建的开销以及回收产生的内容开销,尤其创建对象这是一个很耗时的事情比如IO操作.

拿我们最常见的线程池为例,线程这个对象是可以复用的,程序要执行的任务,这些任务可以交给复用的线程来处理,而线程池创建恰恰又是一个比较耗时的操作,我们通过线程对象的池化技术达到复用线程的目的。

ConcurrentBag实现对象池

池化中需要注意的是多线程中保证线程安全,.NET Framework 4 引入了 System.Collections.Concurrent 命名空间,其中包含多个线程安全且可缩放的集合类。 多个线程可以安全高效地从这些集合添加或删除项,而无需在用户代码中进行其他同步。 编写新代码时,只要将多个线程同时写入到集合时,就使用并发集合类。

ObjectPool

  • Get方法用于从对象池获取到可用对象,如果对象不可用则创建对象并返回出来
  • Return方法用户将对象返回到对象池

public class ObjectPool<T>
{
private ConcurrentBag<T> _object;
private Func<T> _objectGenerator; public ObjectPool(Func<T> objectGenerator) {
_object = new ConcurrentBag<T>();
_objectGenerator = objectGenerator;
}
/// <summary>
/// 取出
/// </summary>
/// <returns></returns>
public T CheckOut() {
T item;
if (_object.TryTake(out item)) return item;
return _objectGenerator();
}
/// <summary>
/// 归还
/// </summary>
/// <param name="obj"></param>
public void CheckIn(T obj) {
_object.Add(obj);
} }

测试


class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource(); // Create an opportunity for the user to cancel.
Task.Run(() =>
{
if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
cts.Cancel();
}); ObjectPool<MyClass> pool = new ObjectPool<MyClass>(() => new MyClass()); // Create a high demand for MyClass objects.
Parallel.For(0, 1000000, (i, loopState) =>
{
MyClass mc = pool.CheckOut();
Console.CursorLeft = 0;
// This is the bottleneck in our application. All threads in this loop
// must serialize their access to the static Console class.
Console.WriteLine("{0:####.####}", mc.GetValue(i)); pool.CheckIn(mc);
if (cts.Token.IsCancellationRequested)
loopState.Stop(); });
Console.WriteLine("Press the Enter key to exit.");
Console.ReadLine();
cts.Dispose();
} class MyClass
{
public int[] Nums { get; set; }
public double GetValue(long i)
{
return Math.Sqrt(Nums[i]);
}
public MyClass()
{
Nums = new int[1000000];
Random rand = new Random();
for (int i = 0; i < Nums.Length; i++)
Nums[i] = rand.Next();
}
} }

这是一个简单的对象池实现,在实际的场景中还需要考虑最小值,最大值,异常处理等等

总结

在创建资源时会消耗一定的系统资源,尤其在及其复杂的结构中效果相对来说是挺明显的,再加上频繁的创建,实例化消耗的资源是很昂贵的.对象池对这些提成是相当有帮助的.

并非任何情况下都需要使用对象池,在复用生成某种对象的操作成为影响性能因素的时候,才适合采用对象池。如果对象池提成性能提高并不重要的话,还是建议不采用对象池,保持代码简单.

参考

https://zh.m.wikipedia.org/zh-cn/%E5%AF%B9%E8%B1%A1%E6%B1%A0%E6%A8%A1%E5%BC%8F

https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/how-to-create-an-object-pool

ASP.NET Core 中的 ObjectPool 对象重用(一)的更多相关文章

  1. ASP.NET Core 中的 ObjectPool 对象重用(二)

    前言 上一篇文章主要介绍了ObjectPool的理论知识,再来介绍一下Microsoft.Extensions.ObjectPool是如何实现的. 核心组件 ObjectPool ObjectPool ...

  2. ASP.NET Core中如何针对一个使用HttpClient对象的类编写单元测试

    原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core? ...

  3. ASP.NET CORE 中使用AutoMapper进行对象映射

    ASP.NET CORE 中使用AutoMapper进行对象映射 1.什么是AutoMapper? AutoMapper是基于对象到对象约定的映射工具,常用于(但并不仅限制于)把复杂的对象模型转为DT ...

  4. ASP.NET Core中的依赖注入(1):控制反转(IoC)

    ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...

  5. [译]ASP.NET Core中使用MediatR实现命令和中介者模式

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html 在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何 ...

  6. Asp.net core中的依赖注入

    使用服务 在Asp.net core的Controller中,可以通过如下两种方式获取系统注入的服务: 构造函数 可以直接在构造函数中传入所依赖的服务,这是非常常见的DI注入方式. public Va ...

  7. (6)ASP.NET Core 中使用IHttpClientFactory发出HTTP请求

    1.HttpClient类使用存在的问题 HttpClient类的使用所存在的问题,百度搜索的文章一大堆,好多都是单纯文字描述,让人感觉不太好理解,为了更好理解HttpClient使用存在的问题,下面 ...

  8. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  9. Asp.net Core中使用Session

    前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...

随机推荐

  1. 如何在Spring Boot中使用Cookies

    一. 导读 本文大纲 读取HTTP Cookie 设置HTTP Cookie 读取所有Cookie[] 为Cookie设置过期时间 Https与Cookie HttpOnly Cookie 删除Coo ...

  2. Android H5混合开发(2):自定义Cordova插件

    前言 Cordova虽然定义了很多基础的插件,供H5端使用原生设备的功能. 但是,如果业务相关的功能,需要提供给H5端使用,那么,就需要我们自定义插件了. 这个"自定义"不是指由A ...

  3. CTR@因子分解机(FM)

    1. FM算法 FM(Factor Machine,因子分解机)算法是一种基于矩阵分解的机器学习算法,为了解决大规模稀疏数据中的特征组合问题.FM算法是推荐领域被验证效果较好的推荐算法之一,在电商.广 ...

  4. python3 自己写的一个小算法(比对中文文本相似度)

    函数使用说明: 函数的三个参数分别是“匹配语句”,“匹配语料”,“相关度”: 匹配语句,和匹配预料中的语句匹配的语句,必须为字符串: 匹配语料,被匹配语句来匹配的语句列表,必须为列表: 相关度,函数只 ...

  5. Redis的使用--基本数据类型的操作命令和应用场景

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! Red ...

  6. Redis过期--淘汰机制的解析和内存占用过高的解决方案

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! Red ...

  7. restapi(9)- caching, akka-http 缓存

    restapi作为前后端交互的枢纽:面对大批量的前端请求,需要确保回复的及时性.使用缓存是一项有效工具.我们可以把多数前端请求的回复response存入缓存,特别是一些需要大量计算才能获取的回复值,更 ...

  8. 利用Nginx中的Upstream模块配置服务器负载均衡

    1. 前言 nginx有一个最大的功能就是可以实现服务器的负载均衡,本篇博文就利用nginx中的upstream模块来配置一个简单的负载均衡.关于nginx的安装和配置文件可以查阅博文:windows ...

  9. [ZJOI2013]K大数查询——整体二分

    题目描述 有N个位置,M个操作.操作有两种,每次操作如果是: 1 a b c:表示在第a个位置到第b个位置,每个位置加上一个数c 2 a b c:表示询问从第a个位置到第b个位置,第C大的数是多少. ...

  10. Linux Shell | 解析xml节点

    01 xml文件 # user.xml <user> <name>Toy</name> <sex>man</sex> <room/&g ...