在协程函数中会反复使用等待下一帧,等待几秒,等待某个条件等功能,但实现这些功能的代价是要实例化一些实现这些功能的类的协程变量。
这些协程变量大多只使用了一次,但是他们实现的功能却相同,从而造成了大量无用的GC浪费效率。
优化就可以从这方面入手,将使用到的协程变量缓存下来,使同一实例化的变量可以被多次使用,避免大量创建临时变量,从而避免大量无用的GC浪费性能。
对于不需要参数的协程变量,如WaitForEndOfFrame,则创建一个全局的协程变量即可
对于有参数的协程变量,我使用了字典根据参数作为键查找协程变量,若没有则再创建,这样可以将GC的性能损失降低不少。
于此同时因为要保存协程变量所以会产生一些内存占用,所以要在确认不用的时候将之删除,并且尽量使用同一参数(比如等待相同的时间)来减少创建协程变量的次数。
Dictionary(字典)使用哈希表结构从而使查找的效率很高,这也正符合我们要实现的多次查找功能 (HashTable也使用了哈希表结构,但是我选择效率较高的Dictionary,对于他们之间的比较可以参考哈希表Hashtable与字典表Dictionary<K,V>的比较)
下面使用全局的静态类实现这一功能:
using System.Collections.Generic;
using UnityEngine;
public static class CoroutineObject
{
//公共Coroutine变量
public static WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
public static WaitForFixedUpdate waitForFixedUpdate = new WaitForFixedUpdate();
//需要用函数获得动态存储的Coroutine变量,采用键值对以免重复添加与快速查找
private static Dictionary<float, WaitForSeconds> waitForSeconds = new Dictionary<float, WaitForSeconds>();
private static Dictionary<float, WaitForSecondsRealtime> waitForSecondsRealtime = new Dictionary<float, WaitForSecondsRealtime>();
private static Dictionary<System.Func<bool>, WaitUntil> waitUntil = new Dictionary<System.Func<bool>, WaitUntil>();
private static Dictionary<System.Func<bool>, WaitWhile> waitWhile = new Dictionary<System.Func<bool>, WaitWhile>();
//获取协程变量
public static WaitForSeconds WaitForSeconds(float k)
{
WaitForSeconds tmp;
if (!waitForSeconds.TryGetValue(k, out tmp))
waitForSeconds.Add(k, (tmp = new WaitForSeconds(k)));
return tmp;
}
public static WaitForSecondsRealtime WaitForSecondsRealtime(float k)
{
WaitForSecondsRealtime tmp;
if (!waitForSecondsRealtime.TryGetValue(k, out tmp))
waitForSecondsRealtime.Add(k, (tmp = new WaitForSecondsRealtime(k)));
return tmp;
}
public static WaitUntil WaitUntil(System.Func<bool> k)
{
WaitUntil tmp;
if (!waitUntil.TryGetValue(k, out tmp))
waitUntil.Add(k, (tmp = new WaitUntil(k)));
return tmp;
}
public static WaitWhile WaitWhile(System.Func<bool> k)
{
WaitWhile tmp;
if (!waitWhile.TryGetValue(k, out tmp))
waitWhile.Add(k, (tmp = new WaitWhile(k)));
return tmp;
}
//删除协程变量,若一个协程变量会被长期使用则尽量不要删除
public static void DeleteWaitForSeconds(float k)
{
waitForSeconds.Remove(k);
}
public static void DeleteWaitForSecondsRealtime(float k)
{
waitForSecondsRealtime.Remove(k);
}
public static void DeleteWaitUntil(System.Func<bool> k)
{
waitUntil.Remove(k);
}
public static void DeleteWaitWhile(System.Func<bool> k)
{
waitWhile.Remove(k);
}
//清空协程变量
public static void ClearWaitForSeconds()
{
waitForSeconds.Clear();
}
public static void ClearWaitForSecondsRealtime()
{
waitForSecondsRealtime.Clear();
}
public static void ClearWaitUntil()
{
waitUntil.Clear();
}
public static void ClearWaitWhile()
{
waitWhile.Clear();
}
}
使用方法:
- 将协程中yield return new Waitxxxx(xxx) 替换为 yield return CoroutineObject.Waitxxx(xxx) 即可。
- 在确认不适用该有参协程变量的时候可以通过 CoroutineObject.DeleteWaitxxx(key) 将之删除,以免消耗内存空间
- 可以使用 CoroutineObject.ClearWaitxxx() 将该类型的协程变量全部删除