UniRx-unirx中的对象池
UniRx-unirx中的对象池
一、对象池模式
1.概念
定义一个池对象,其包含了一组可重用对象。 其中每个可重用对象都支持查询“使用中”状态,说明它是不是“正在使用”。 池被初始化时,它就创建了整个对象集合(通常使用一次连续的分配),然后初始化所有对象到“不在使用中”状态。
当你需要新对象,向池子要一个。 它找到一个可用对象,初始化为“使用中”然后返回。 当对象不再被需要,它被设置回“不在使用中”。 通过这种方式,可以轻易地创建和销毁对象而不必分配内存或其他资源。
2.优点
游戏中会出现诸如子弹,粒子特效等大量的单一资源。频繁的创建和销毁会浪费很多性能并且产生大量的内存碎片。对象池模式放弃单独地分配和释放对象,从固定的池中重用对象,以提高性能和内存使用率。

3.何时使用
- 需要频繁创建和销毁对象。
- 对象大小相仿。
- 在堆上进行对象内存分配十分缓慢或者会导致内存碎片。
- 每个对象都封装了像数据库或者网络连接这样很昂贵又可以重用的资源。
4.注意
- 可以将创建对象和销毁对象平缓的放到多个帧处理
- 动态的维护池子的大小
UniRx中的对象池使用
1.案例
1.1 prefab上脚本
using System;
using UniRx;
using UnityEngine;
using Random = UnityEngine.Random;
public class PoolObject : MonoBehaviour
{
public IObservable<Unit> AsyncAction()
{
var colorstream = Observable.Timer(TimeSpan.FromSeconds(0.2f));
colorstream.Subscribe(_ =>
{
GetComponent<Renderer>().material.color = Color.Lerp(Color.red, Color.blue, Random.Range(0.0f,1.0f));
});
var positiontream = Observable.Timer(TimeSpan.FromSeconds(0.2f));
positiontream.Subscribe(_ =>
{
transform.localPosition=Vector3.one*Random.Range(-5f,5f);
});
var unit = Observable.ReturnUnit();
var allStream = Observable.WhenAll(unit);
allStream.Subscribe(_ =>
{
Debug.Log("QAQ");
});
return Observable.ReturnUnit();
}
}
2.自定义对象池
using System;
using UniRx;
using UniRx.Toolkit;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
public class UniRxObjectPool : ObjectPool<PoolObject>
{
private GameObject _prefab;
public UniRxObjectPool(GameObject prefab)
{
this._prefab = prefab;
}
protected override PoolObject CreateInstance()
{
var gameObj = Object.Instantiate(_prefab);
return gameObj.GetComponent<PoolObject>();
}
protected override void OnBeforeRent(PoolObject instance)
{
base.OnBeforeRent(instance);
Debug.Log($"从池子中取出:{instance.name}");
}
// 在对象返回到池子里面之前回调
protected override void OnBeforeReturn(PoolObject instance)
{
base.OnBeforeReturn(instance);
Debug.Log($" 返回 {instance} 到池子里面");
}
// 在对象从池子里面移除回调
protected override void OnClear(PoolObject instance)
{
base.OnClear(instance);
Debug.Log($"从池子里面移除 {instance}");
}
}
3.对象池调用
using System;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
public class No11_ObjectPool : MonoBehaviour
{
[SerializeField]
private GameObject mPoolPrefab;
[SerializeField]
private Button mBtnSpawn;
[SerializeField]
private Button mBtnShrink;
[SerializeField]
private Button mBtnClear;
void Start()
{
UniRxObjectPool pool = new UniRxObjectPool(mPoolPrefab);
mBtnSpawn.OnClickAsObservable().Subscribe(_ =>
{
for (int i = 0; i < 5; i++)
{
//从池中获取实例,出栈
var poolObj = pool.Rent();
poolObj.AsyncAction().Subscribe(next =>
{
Debug.Log("mult thread run");
});
//根据对象创建的频率来扩张池子大小
Observable.TimerFrame(300).Subscribe(f =>
{
//回收对象到池子
pool.Return(poolObj);
});
}
});
mBtnShrink.OnClickAsObservable().Subscribe(_ =>
{
// 手动回收对象池子, 第一个参数是回收比例,第二个参数是保存最小数量
//pool.Shrink(0.6f, 1);
// 自动回收对象池子,3秒检查一次进行回收,销毁实例,缩小池子大小,保持最小数
pool.StartShrinkTimer(TimeSpan.FromSeconds(3f), 0.6f, 2);
});
mBtnClear.OnClickAsObservable().Subscribe(_ =>
{
//清理对象池,destroy所有对象
pool.Clear();
});
}
}
2.源码
1.回收实例到对象池
将实例入栈,可以在OnBeforeReturn中对将要回收的实例进行以下操作,比如隐藏。
- /// <summary>
- /// Return instance to pool.
- /// </summary>
- public void Return(T instance)
- {
- if (isDisposed) throw new ObjectDisposedException("ObjectPool was already disposed.");
- if (instance == null) throw new ArgumentNullException("instance");
- if (q == null) q = new Queue<T>();
- if ((q.Count + 1) == MaxPoolCount)
- {
- throw new InvalidOperationException("Reached Max PoolSize");
- }
- OnBeforeReturn(instance);
- q.Enqueue(instance);
- }
2.缩减对象池
设置一个对象池保有对象实例的最小值,然后不断按照一定的比例系数出栈操作来缩减池子大小
- /// <summary>
- /// Trim pool instances.
- /// </summary>
- /// <param name="instanceCountRatio">0.0f = clear all ~ 1.0f = live all.</param>
- /// <param name="minSize">Min pool count.</param>
- /// <param name="callOnBeforeRent">If true, call OnBeforeRent before OnClear.</param>
- public void Shrink(float instanceCountRatio, int minSize, bool callOnBeforeRent = false)
- {
- if (q == null) return;
- if (instanceCountRatio <= 0) instanceCountRatio = 0;
- if (instanceCountRatio >= 1.0f) instanceCountRatio = 1.0f;
- var size = (int)(q.Count * instanceCountRatio);
- size = Math.Max(minSize, size);
- while (q.Count > size)
- {
- var instance = q.Dequeue();
- if (callOnBeforeRent)
- {
- OnBeforeRent(instance);
- }
- OnClear(instance);
- }
- }
- /// <summary>
- /// If needs shrink pool frequently, start check timer.
- /// </summary>
- /// <param name="checkInterval">Interval of call Shrink.</param>
- /// <param name="instanceCountRatio">0.0f = clearAll ~ 1.0f = live all.</param>
- /// <param name="minSize">Min pool count.</param>
- /// <param name="callOnBeforeRent">If true, call OnBeforeRent before OnClear.</param>
- public IDisposable StartShrinkTimer(TimeSpan checkInterval, float instanceCountRatio, int minSize, bool callOnBeforeRent = false)
- {
- //UniRx Interval定间隔调用
- return Observable.Interval(checkInterval)
- .TakeWhile(_ => !isDisposed)//TakeWhile(condition) conditon为false时终止,且不包含临界的item
- .Subscribe(_ =>
- {
- Shrink(instanceCountRatio, minSize, callOnBeforeRent);
- });
- }
二、小结
对象池的好处就是提高性能和内存使用率,适合诸如子弹,弹幕,粒子效果(另一种优化技术GPU Intance),小怪群等。它和享元模式的区别类似于享元模式接头缝合怪,很多人用一个头,它则是可量产回收的机械克隆人。
UniRx-unirx中的对象池的更多相关文章
- Java中的对象池技术
java中的对象池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间.对象池其实也就是一个内存 ...
- Unity编程标准导引-3.4 Unity中的对象池
本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan Unity编程标准导引-3.4 Unity中的对象池 本节通过一个简单的射击子弹的示例来介绍T ...
- Java 中的对象池实现
点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. 最近在 ...
- 关于tomcat中Servlet对象池
Servlet在不实现SingleThreadModel的情况下运行时是以单个实例模式,如下图,这种情况下,Wrapper容器只会通过反射实例化一个Servlet对象,对应此Servlet的所有客户端 ...
- .net core中的对象池
asp.net core中通过扩展库的方式提供给了一个标准的对象池ObjectPool,定义在Microsoft.Extensions.ObjectPool.dll 程序集中.它本身是个纯虚的抽象类, ...
- GameObjectPool——Unity中的对象池
这里介绍一种对象池的写法.它的优点在于无论取出还是插入游戏物体都是常数量时间. using UnityEngine; using System.Collections; using System.Co ...
- Egret中的对象池ObjectPool
为了可以让对象复用,防止大量重复创建对象,导致资源浪费,使用对象池来管理. 对象池具体含义作用,自行百度. 一 对象池A 二 对象池B 三 字符串key和对象key的效率 一 对象池A /** * 对 ...
- Egret中的对象池Pool
为了可以让对象复用,防止大量重复创建对象,导致资源浪费,使用对象池来管理. 一 对象池A 二 对象池B 一 对象池A 1. 支持传入构造函数 2. 支持预先创建对象 3. 支持统一执行函数 /** * ...
- Unity中的万能对象池
本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan Unity编程标准导引-3.4 Unity中的万能对象池 本节通过一个简单的射击子弹的示例来介 ...
- 对象池在 .NET (Core)中的应用[2]: 设计篇
<编程篇>已经涉及到了对象池模型的大部分核心接口和类型.对象池模型其实是很简单的,不过其中有一些为了提升性能而刻意为之的实现细节倒是值得我们关注.总的来说,对象池模型由三个核心对象构成,它 ...
随机推荐
- [GPT] php查询mongo,触发了 operation exceeded time limit
"operation exceeded time limit"错误通常意味着查询所需的时间超过了MongoDB实例配置的操作超时限制. 这可以是由于查询需要处理大量数据或没有正 ...
- dotnet6 C# 一个国内还能用的 NTP 时间校准客户端的实现
本文来记录一个我自己在使用的 NTP 时间校准客户端的实现 核心方法是在国内使用 腾讯 和 阿里 提供的 NTP 时间服务器来获取网络时间,如果连接不上,再依次换成 国家服务器 和 中国授时 服务,如 ...
- Azure 无服务器 Function 函数计算服务 dotnet core 3.1 创建和部署入门
本文用的是 世纪互联 的 Azure.cn 版本,这个版本因为是在国内,所以网速会快超级超级多.使用 世纪互联 的版本需要一块钱哦,用一块钱就能进入一个月的免费试用.本文主要告诉小伙伴如何使用 Azu ...
- MQTT GUI 客户端 可视化管理工具
MQTT GUI 客户端 可视化管理工具 介绍 多标签页管理,同时打开多个连接 提供原生性能,并且比使用 Electron 等 Web 技术开发的同等应用程序消耗的资源少得多 支持 MQTT v5.0 ...
- 鸿蒙HarmonyOS实战-ArkUI事件(键鼠事件)
前言 键鼠事件是指在计算机操作中,用户通过键盘和鼠标来与计算机进行交互的行为.常见的键鼠事件包括按下键盘上的键.移动鼠标.点击鼠标左键或右键等等.键鼠事件可以触发许多不同的操作,比如在文本编辑器中输入 ...
- [ABC345D] Tiling 位运算の极致运用
[ABC345D] Tiling 原题解地址:Editorial by Kiri8128 神写法. 将 \(H \times W\) 的网格展开为 \(H \times (W + 1)\) 的序列, ...
- 关于Web的欢迎页面的开发设置
关于Web的欢迎页面的开发设置 每博一文案 命运总是不如人愿.但往往是在无数的痛苦中,在重重的矛盾和艰辛中,才是人成熟起来. 一次邂逅,一次目光的交融,就是永远的合二为一,就是与上帝的契约:总是风暴雷 ...
- 【web安全】修改和配置tomcat版本信息
场景 目前网络安全的越来越受重视,tomcat作为重要的web容器被广泛应用,如何隐藏信息保证.在开放网络世界中,不易被攻击. 操作思路 1.进入Tomcat文件中的lib文件夹,将catalina. ...
- 【转载】超级系统工具Sysdig,比 strace、tcpdump、lsof 加起来还强大
可以用sysdig命令做很多很酷的事情 网络 查看占用网络带宽最多的进程 sysdig -c topprocs_net 显示主机192.168.0.1的网络传输数据 as binary: sysdig ...
- NASM语法
NASM汇编语言的语法很简单,由4部分组成: label:instruction operands; comment 这4部分都是可选的.一条语句可以没有label,没有comment,甚至连inst ...