手写工具-对象池
1.什么时候需要对象池?
在回频繁创建与销毁对象的程序里,如果使用了对象池复用对象可以明显提升效率,原因很容易理解这样做剩下对象创建的开销,这即一种常见的优化思想-**池化技术,**常见场景举例:
- web 框架比如 gin 里利用池化对象提升性能
- 游戏开发里 N 多子弹的出现消失,复用子弹对象
- golang 提供的 sync.pool
2.用 JS 手写一个对象池
对象池名字很贴切,即我们需要一个对象的时候从池子里取出来即可以使用,当我们不需要的时候再将对象放回池子,就这样对象池里存储着一堆对象。当取对象时如果池子里的都用完了,我们就可以内部走新建对象传递出来,所以对象池比较重要的点就是按照需要设计合适的池子大小,预防占用太多内存。
/**
* 对象池
*
* @description
* 避免频繁gc
*
*
* @example
*
* ```
* //初始化池子
* let pool = new ObjectPool({
* create: () => new Float32Array(4),
* reInit: (item: Float32Array) => {
* for (let i = 0; i < item.length; i++) {
* item[i] = 0;
* }
* }
* });
*
* //创建
* let ins = pool.create();
*
* //回收
* pool.recycle(ins);
*
* //清空池子
* pool.clear();
* ```
*/
export class ObjectPool<T> {
private _create: () => T;
private _reInit: (obj: T) => void;
private _pool: T[] = [];
get size() { return this._pool.length }
constructor(
options: {
create: () => T,//创建对象操作
reInit?: (obj: T) => void,//取对象时,可以进行初始化值操作
initSize?: number,//初始池子大小
}) {
this._create = options.create;
this._reInit = options?.reInit;
if (options.initSize != null) {
this._pool = [...new Array(options.initSize)].map(item => this._create())
}
}
/**
* 创建对象
*/
instantiate(reInit = true) {
if (this._pool.length == 0) {
return this._create();
} else {
let item = this._pool.shift();
if (reInit) this._reInit?.(item);
return item;
}
}
/**
* 回收对象
* @param obj
*/
recycle(obj: T) {
this._pool.push(obj);
}
/**
* 清空池子
*/
clear() {
this._pool = [];
}
}