字符串优化加强版--StringPool

之前写过一篇string字符串优化相关的文章,但是里面是使用一个static静态变量。先看下之前的代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Lemon { public class QString { private static StringBuilder CommonStringBuilder = new StringBuilder(); private static StringBuilder InternalStringBuilder = new StringBuilder(); public static StringBuilder GetStringBuilder() { CommonStringBuilder.Remove(0, CommonStringBuilder.Length); return CommonStringBuilder; } public static string Concat(string s1, string s2) { InternalStringBuilder.Remove(0, InternalStringBuilder.Length); InternalStringBuilder.Append(s1); InternalStringBuilder.Append(s2); return InternalStringBuilder.ToString(); } public static string Concat(string s1, string s2, string s3) { InternalStringBuilder.Remove(0, InternalStringBuilder.Length); InternalStringBuilder.Append(s1); InternalStringBuilder.Append(s2); InternalStringBuilder.Append(s3); return InternalStringBuilder.ToString(); } public static string Format(string src, params object[] args) { InternalStringBuilder.Remove(0, InternalStringBuilder.Length); InternalStringBuilder.AppendFormat(src, args); return InternalStringBuilder.ToString(); } } }
QString里面的stringbuilder一共是两个,一个是给外部用的是CommonStringBuilder,一个是内部使用的InternalStringBuilder。
private static StringBuilder CommonStringBuilder = new StringBuilder(); private static StringBuilder InternalStringBuilder = new StringBuilder();
之前一直是在Unity里面主线程上面使用的,没有用到多线程。昨天写东西用到了多线程,因此这里仅一个静态的stringbuilder已经无法满足需求了,因此StringPool产生了,底层实现其实是对stringbuilder使用了pool形式。
大家还记得之前的ObjectPool的文章么,今天就使用ObjectPool来封装一个StringBuilderPool。先贴上ObjectPool的代码。
/** * Author:onelei * Copyright © 2019 - 2020 ONELEI. All Rights Reserved */ using System.Collections.Generic; using UnityEngine.Events; public class ObjectPool<T> where T : new() { private readonly Stack<T> m_Stack = new Stack<T>(); private readonly UnityAction<T> m_ActionOnGet; private readonly UnityAction<T> m_ActionOnRelease; public int countAll { get; private set; } public int countActive { get { return countAll - countInactive; } } public int countInactive { get { return m_Stack.Count; } } public ObjectPool(UnityAction<T> actionOnGet, UnityAction<T> actionOnRelease) { m_ActionOnGet = actionOnGet; m_ActionOnRelease = actionOnRelease; } public T Get() { T element; if (m_Stack.Count == 0) { element = new T(); countAll++; } else { element = m_Stack.Pop(); } if (m_ActionOnGet != null) m_ActionOnGet(element); return element; } public void Release(T element) { if (m_Stack.Count > 0 && ReferenceEquals(m_Stack.Peek(), element)) QLog.LogError("Internal error. Trying to destroy object that is already released to pool."); if (m_ActionOnRelease != null) m_ActionOnRelease(element); m_Stack.Push(element); } }
ObjectPool代码来自UGUI源码。
下面我们看看StringPool的代码如何实现
/** * Author:onelei * Copyright © 2019 - 2020 ONELEI. All Rights Reserved */ using System.Text; public static class StringPool { private static int MaxCount = 100; // Object pool to avoid allocations. private static readonly ObjectPool<StringBuilder> Pool = new ObjectPool<StringBuilder>(Clear, null); static void Clear(StringBuilder s) { if (Pool.countAll >= MaxCount) { QLog.LogError("Pool count reach to MaxCount."); } s.Remove(0, s.Length); } public static StringBuilder GetStringBuilder() { StringBuilder stringBuilder = Pool.Get(); return stringBuilder; } public static void Release(StringBuilder toRelease) { if (Pool.countAll >= MaxCount) { QLog.LogError("Pool count reach to MaxCount."); } Pool.Release(toRelease); } public static string Concat(string s1, string s2) { StringBuilder stringBuilder = Pool.Get(); stringBuilder.Append(s1); stringBuilder.Append(s2); string result = stringBuilder.ToString(); Release(stringBuilder); return result; } public static string Concat(string s1, string s2, string s3) { StringBuilder stringBuilder = Pool.Get(); stringBuilder.Append(s1); stringBuilder.Append(s2); stringBuilder.Append(s3); string result = stringBuilder.ToString(); Release(stringBuilder); return result; } public static string Format(string src, params object[] args) { StringBuilder stringBuilder = Pool.Get(); stringBuilder.Remove(0, stringBuilder.Length); stringBuilder.AppendFormat(src, args); string result = stringBuilder.ToString(); Release(stringBuilder); return result; } }
我们在StringPool里面使用ObjectPool<StringBuilder>保存了一个Pool对象池。
// Object pool to avoid allocations. private static readonly ObjectPool<StringBuilder> Pool = new ObjectPool<StringBuilder>(Clear, null); static void Clear(StringBuilder s) { s.Remove(0, s.Length); }
同时在Pool的Get函数里面传入Clear函数,在获取到StringBuilder的时候执行Clear函数清除里面的数据。
接下来我们来看如何使用,其实和之前区别并不大,函数接口都没有改动,我们只需要改函数的内部实现即可,先看下Concat函数
public static string Concat(string s1, string s2) { StringBuilder stringBuilder = Pool.Get(); stringBuilder.Append(s1); stringBuilder.Append(s2); string result = stringBuilder.ToString(); Release(stringBuilder); return result; }
首先Pool.Get()在缓存池里面获取一个StringBuilder变量,在操作好之后执行Release函数,将其放回池中。同理Format函数亦是如此。
我们注意到ObjectPool里面有这三个变量
public int countAll { get; private set; } public int countActive { get { return countAll - countInactive; } } public int countInactive { get { return m_Stack.Count; } }
countAll是在每次new一个StringBuilder的时候自动加一,也就是池中的对象总数。
countInactive是在每次Release的时候放回m_Stack里面的,也就是被放回池中的,未使用对象。
剩下的countActive就是已经被利用的对象数量。
我们为了防止池没有被合理使用,我们可以设置一个池中的对象总数,作为代码防护,防止内存泄漏。大部分情况下是对象在用完之后,没有被及时执行Release函数,导致池中不断的new一个对象出来,因此我们可以在Get函数里面做一个安全判断,当超过池中最大容量的时候,抛出一个错误。
static void Clear(StringBuilder s) { if (Pool.countAll >= MaxCount) { QLog.LogError("Pool count reach to MaxCount."); } s.Remove(0, s.Length); }
我们在Get的函数的回调函数Clear里面添加以上判断即可。
如果本文对你有所帮助,欢迎赞赏~~~
==================
《游戏AI程序设计实战》作者
微信公众号:Unity游戏开发笔记 Github:https://github.com/onelei
优快云:https://blog.youkuaiyun.com/onelei1994
QQ交流群:754814245
欢迎支持我的新书《游戏AI程序设计实战》 https://item.jd.com/12520141.html
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值