前言

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

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

对象池的优势

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

    Function: /// <summary> /// ToInt /// </summary> /// <param name="str">& ...

  2. Linux之ELF文件初探

    对比windowsPE文件与概述 在windows中可执行文件是pe文件格式,Linux中可执行文件是ELF文件,其文件格式是ELF文件格式,在Linux下的ELF文件除了可执行文件(Excutabl ...

  3. sql中实现先排序后分组

    数据表结构和数据如下: CREATE TABLE `commun_message_chat_single` ( `id` ) NOT NULL AUTO_INCREMENT, `chat_id` ) ...

  4. beacon帧字段结构最全总结(一)——beacon基本结构

    一.beacon帧主要结构 二.MAC  header 1.Version:版本号,目前为止802.11只有一个版本,所以协议编号为0 2.Type:定义802.11帧类型,802.11帧分为管理帧( ...

  5. 关闭redis持久化功能

    关闭redis持久化功能持久化会报如下信息 会影响硬盘写入性能 所以没什么用 就关掉吧 修改redis配置文件,redis.conf 第115行左右. 1.注释掉原来的持久化规则 <pre> ...

  6. CentOS7 reset脚本,用于初始化新的虚拟机

    能用,有待完善 CentOS7测试 哈哈 #!/bin/bash #************************************************************** #Au ...

  7. 2、linux基础-面试题

    自己写的答案 1.1GB 2.4 3.ubuntu.dbian.Fedora 4.系统.硬件.clock -w 5.文件 6.uname -a 7.centos是redhat的社区版,redhat是商 ...

  8. PHP经典面试题:如何保证缓存与数据库的双写一致性?

    只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 面试题剖析 一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说 ...

  9. java编程思想第四版第十一章习题

    第一题 package net.mindview.holding.test1; import java.util.ArrayList; import java.util.List; /** * 沙鼠 ...

  10. Python 常用模块系列(2)--time module and datatime module

    import time print (help(time)) #time帮助文档 1. time模块--三种时间表现形式: 1° 时间戳--如:time.time()  #从python创立以来,到当 ...