ASP.NET Core 中的 ObjectPool 对象重用(二)
前言
上一篇文章主要介绍了ObjectPool的理论知识,再来介绍一下Microsoft.Extensions.ObjectPool是如何实现的.

核心组件
ObjectPool
ObjectPool是一个泛型抽象接口,他抽象了两个方法Get和Return
- Get方法用于从对象池获取到可用对象,如果对象不可用则创建对象并返回出来
- Return方法用户将对象返回到对象池
/// <summary>
/// A pool of objects.
/// </summary>
/// <typeparam name="T">The type of objects to pool.</typeparam>
public abstract class ObjectPool<T> where T : class
{
/// <summary>
/// Gets an object from the pool if one is available, otherwise creates one.
/// </summary>
/// <returns>A <typeparamref name="T"/>.</returns>
public abstract T Get();
/// <summary>
/// Return an object to the pool.
/// </summary>
/// <param name="obj">The object to add to the pool.</param>
public abstract void Return(T obj);
}
ObjectPoolProvider
ObjectPoolProvider是一个抽象接口他内置了Create的泛型方法和Create的泛型抽象方法,他是一个基于默认策略的。
/// <summary>
/// A provider of <see cref="ObjectPool{T}"/> instances.
/// </summary>
public abstract class ObjectPoolProvider
{
/// <summary>
/// Creates an <see cref="ObjectPool"/>.
/// </summary>
/// <typeparam name="T">The type to create a pool for.</typeparam>
public ObjectPool<T> Create<T>() where T : class, new()
{
return Create<T>(new DefaultPooledObjectPolicy<T>());
}
/// <summary>
/// Creates an <see cref="ObjectPool"/> with the given <see cref="IPooledObjectPolicy{T}"/>.
/// </summary>
/// <typeparam name="T">The type to create a pool for.</typeparam>
public abstract ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy) where T : class;
}
IPooledObjectPolicy
IPooledObjectPolicy是一个泛型接口,提供策略管理对象池,该类也定义了两个方法Create和Return以提供策略实现
- Create用于创建相关的类实例
- Return用于将已经使用完的对象放回到池中,包括重置对象状态以及是否能够放回到池中
/// <summary>
/// Represents a policy for managing pooled objects.
/// </summary>
/// <typeparam name="T">The type of object which is being pooled.</typeparam>
public interface IPooledObjectPolicy<T>
{
/// <summary>
/// Create a <typeparamref name="T"/>.
/// </summary>
/// <returns>The <typeparamref name="T"/> which was created.</returns>
T Create();
/// <summary>
/// Runs some processing when an object was returned to the pool. Can be used to reset the state of an object and indicate if the object should be returned to the pool.
/// </summary>
/// <param name="obj">The object to return to the pool.</param>
/// <returns><code>true</code> if the object should be returned to the pool. <code>false</code> if it's not possible/desirable for the pool to keep the object.</returns>
bool Return(T obj);
}
PooledObjectPolicy是一个泛型抽象类,并且实现了IPooledObjectPolicy,对外提供了两个抽象方法
public abstract class PooledObjectPolicy<T> : IPooledObjectPolicy<T>
{
public abstract T Create();
public abstract bool Return(T obj);
}
实现机制
DefaultObjectPool
DefaultObjectPool实现了ObjectPool,Interlocked.CompareExchange(ref _firstItem, null, item)将_firstItem的值和item的值比较,相等则用null替换_firstItem,否则不操作,不管替换还是不替换返回的都是原来保存在_firstItem的值。
Interlocked可以为多个线程共享的变量提供原子操作。
- Interlocked.Increment:以原子操作的形式递增指定变量的值并存储结果。
- Interlocked.Decrement以原子操作的形式递减指定变量的值并存储结果。
- Interlocked.Add以原子操作的形式,添加两个整数并用两者的和替换第一个整数
public override T Get()
{
var item = _firstItem;
if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item)
{
var items = _items;
for (var i = 0; i < items.Length; i++)
{
item = items[i].Element;
if (item != null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item)
{
return item;
}
}
item = Create();
}
return item;
}
public override void Return(T obj)
{
if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
{
if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null)
{
var items = _items;
for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i)
{
}
}
}
}
DefaultObjectPoolProvider
DefaultObjectPoolProvider重写了ObjectPoolProvider中Crearte方法,
设置了默认的对象最大数量只能用的是默认的Environment.ProcessorCount * 2(CPU处理器的两倍)
/// <summary>
/// The default <see cref="ObjectPoolProvider"/>.
/// </summary>
public class DefaultObjectPoolProvider : ObjectPoolProvider
{
/// <summary>
/// The maximum number of objects to retain in the pool.
/// </summary>
public int MaximumRetained { get; set; } = Environment.ProcessorCount * 2;
/// <inheritdoc/>
public override ObjectPool<T> Create<T>(IPooledObjectPolicy<T> policy)
{
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
if (typeof(IDisposable).IsAssignableFrom(typeof(T)))
{
return new DisposableObjectPool<T>(policy, MaximumRetained);
}
return new DefaultObjectPool<T>(policy, MaximumRetained);
}
}
DisposableObjectPool
DisposableObjectPool继承了DefaultObjectPool以及实现了IDisposable用于手动的回收对象
public void Dispose()
{
_isDisposed = true;
DisposeItem(_firstItem);
_firstItem = null;
ObjectWrapper[] items = _items;
for (var i = 0; i < items.Length; i++)
{
DisposeItem(items[i].Element);
items[i].Element = null;
}
}
private void DisposeItem(T item)
{
if (item is IDisposable disposable)
{
disposable.Dispose();
}
}
LeakTrackingObjectPool
LeakTrackingObjectPool实现了ObjectPool,它定义了ConditionalWeakTable他是一个弱引用字典,ConditionalWeakTable<TKey,TValue> 中的所有 Key 和所有的 Value 都是弱引用的,并且会在其 Key 被回收或者 Key 和 Value 都被回收之后自动从集合中消失。这意味着当你使用它来为一个类型附加一些字段或者属性的时候完全不用担心内存泄漏的问题
public class LeakTrackingObjectPool<T> : ObjectPool<T> where T : class
{
private readonly ConditionalWeakTable<T, Tracker> _trackers = new ConditionalWeakTable<T, Tracker>();
private readonly ObjectPool<T> _inner;
public LeakTrackingObjectPool(ObjectPool<T> inner)
{
if (inner == null)
{
throw new ArgumentNullException(nameof(inner));
}
_inner = inner;
}
public override T Get()
{
var value = _inner.Get();
_trackers.Add(value, new Tracker());
return value;
}
public override void Return(T obj)
{
Tracker tracker;
if (_trackers.TryGetValue(obj, out tracker))
{
_trackers.Remove(obj);
tracker.Dispose();
}
_inner.Return(obj);
}
private class Tracker : IDisposable
{
private readonly string _stack;
private bool _disposed;
public Tracker()
{
_stack = Environment.StackTrace;
}
public void Dispose()
{
_disposed = true;
GC.SuppressFinalize(this);
}
~Tracker()
{
if (!_disposed && !Environment.HasShutdownStarted)
{
Debug.Fail($"{typeof(T).Name} was leaked. Created at: {Environment.NewLine}{_stack}");
}
}
}
}
参考
https://blog.walterlv.com/post/conditional-weak-table.html
https://www.cnblogs.com/edison0621/p/11747912.html
ASP.NET Core 中的 ObjectPool 对象重用(二)的更多相关文章
- ASP.NET Core 中的 ObjectPool 对象重用(一)
前言 对象池是一种设计模式,一个对象池包含一组已经初始化过且可以使用的对象,而可以在有需求时创建和销毁对象.池的对象可以从池中取得对象,对其进行操作处理,并在不需要时归还给池子而非直接销毁他,他是一种 ...
- ASP.NET Core中如何针对一个使用HttpClient对象的类编写单元测试
原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core? ...
- ASP.NET CORE 中使用AutoMapper进行对象映射
ASP.NET CORE 中使用AutoMapper进行对象映射 1.什么是AutoMapper? AutoMapper是基于对象到对象约定的映射工具,常用于(但并不仅限制于)把复杂的对象模型转为DT ...
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...
- [译]ASP.NET Core中使用MediatR实现命令和中介者模式
作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9866068.html 在本文中,我将解释命令模式,以及如何利用基于命令模式的第三方库来实现它们,以及如何 ...
- Asp.net core中的依赖注入
使用服务 在Asp.net core的Controller中,可以通过如下两种方式获取系统注入的服务: 构造函数 可以直接在构造函数中传入所依赖的服务,这是非常常见的DI注入方式. public Va ...
- (6)ASP.NET Core 中使用IHttpClientFactory发出HTTP请求
1.HttpClient类使用存在的问题 HttpClient类的使用所存在的问题,百度搜索的文章一大堆,好多都是单纯文字描述,让人感觉不太好理解,为了更好理解HttpClient使用存在的问题,下面 ...
- ASP.NET Core 中的那些认证中间件及一些重要知识点
前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...
- Asp.net Core中使用Session
前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...
随机推荐
- python的多线程和多进程(一)
在进入主题之前,我们先学习一下并发和并行的概念: --并发:在操作系统中,并发是指一个时间段中有几个程序都处于启动到运行完毕之间,且这几个程序都是在同一个处理机上运行.但任一时刻点上只有一个程序在处理 ...
- 设计模式C++描述----04.观察者(Observer)模式
一. 概述 Observer 模式要解决的问题为:建立一个一(Subject)对多(Observer)的依赖关系,并且做到当“一”变化的时候,依赖这个“一”的多也能够同步改变. Sbuject 相当于 ...
- linux文本编辑器教学
linux常见服务 一. 文本编辑器 vi vim是vi增强版 vim需要安装 sudo apt-get -y install vim 1 vim的三种工作模式 1 编辑模式 命令模式=>编辑模 ...
- 2019.11.11&12题解
Day1 考的不是很好,T1T2没区分度,T3想的太少,考试后期几乎都是在摸鱼,bitset乱搞也不敢打,只拿到了35分,跟前面的差距很大 A. 最大或 标签: 二进制+贪心 题解: 首先x,y中一定 ...
- P3128 [USACO15DEC]最大流
秒切树上查分....(最近一次集训理解的东西) 但是,我敲了半小时才切掉这道题.... 我一直迷在了“边差分”和“点差分”的区别上. 所以,先说一下此题,再说一下区别. 首先,想到差分很容易. 然后, ...
- 11、pytest -- 测试的参数化
目录 1. @pytest.mark.parametrize标记 1.1. empty_parameter_set_mark选项 1.2. 多个标记组合 1.3. 标记测试模块 2. pytest_g ...
- UiPath之基础知识(一)
各位小伙伴,大家好.在10月份小U的微信订阅号做了一个投票,主题是UiPath目前已经掌握的程度. 从投票的结果来看,有一半以上的人还是刚刚起步,为了帮助刚刚起步的小伙伴,准备陆续发布一些基础性的内容 ...
- 2019年10月13日 linux习题 wangqingchao
1. GUN的含义是: GNU's Not UNIX . 2. Linux一般有3个主要部分:内核.命令解释层.实用工具. 3.POSIX是可携式操作系统接口的缩写,重点在规范核心与应用程序之间的接口 ...
- esp8266 smartconfig-智能配网分析和使用及注意事项
基本知识: 乐鑫⾃主研发的 ESP-TOUCH 协议采⽤的是 Smart Config(智能配置)技术,帮助⽤户将 采⽤ ESP8266EX 和 ESP32 的设备(以下简称“设备”)连接⾄ Wi ...
- RHEL7-Vsftpd匿名用户
实现:匿名用户创建目录,可以上传.下载文件,但是不可删除文件,禁止本地用户登陆. Vsftpd.conf部分参数 第一步:虚拟机挂载镜像 略 第二步:执行挂载命令 略 第三步:编写yum仓库文件 略 ...