最近在读《Unity性能优化(第三版)》,看到其中的第2.11.4章节的全局消息管理器里 MessagingSystem 编写的代码时,注意到他没有使用协程,而是使用了System.Diagnostics.Stopwatch,来进行对单帧运行过长的循环进行分帧处理的操作,觉得挺有趣就在这儿记录一下(顺便纠正书中的一处忘记用Reset清空累计计时的错误)。
耗时案例:
首先我们在写一个比较耗时的循环(这里用到了臭名昭著但又难以割舍的Find方法),然后我们运行会发现Unity要卡好久才会输出 End:
private System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
private int i = 0;
void Update()
{
if (i == 0)
{
Debug.Log("Start");
}
while (i<20000000)
{
// 写一个稍微耗时的操作在循环体里
GameObject obj = GameObject.Find("Curoa_icon");
i++;
}
if (i== 20000000)
{
i++;
Debug.Log("End");
}
}
然后大约花费了6s左右,这期间这一帧就卡住了:
使用Stopwatch的改善方法:
然后我们用Stopwatch来进行改善——假如该次Update中的循环累计时间超过了100毫秒,那么我们中断该帧,在下一帧中处理剩下的循环:
private System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
private int i = 0;
void Update()
{
timer.Start();
if (i == 0)
{
Debug.Log("Start");
}
while (i<20000000)
{
if (timer.Elapsed.Milliseconds > 100)
{
// 该帧超时了我们就输出一下
Debug.Log("timerStop " + timer.Elapsed.Milliseconds);
Debug.Log("i = " + i);
timer.Stop();
timer.Reset(); // 原书这里忘记reset了,如果漏了可能会导致Elapsed没有清空累计计时;
return;
}
// 写一个稍微耗时的操作在循环体里
GameObject obj = GameObject.Find("Curoa_icon");
i++;
}
if (i== 20000000)
{
i++;
Debug.Log("End");
}
}
运行一下会发现,原本会卡住的单帧被拆分到大约80帧中完成了,每帧只进行了循环中的一部分:
最后推荐一下Davide Aversa和Chris Dickinson编写的这本书,毕竟这年头多看点儿纸质书有益于舒缓大脑Σ_(꒪ཀ꒪」∠)_: