前言
- 原创文章,转载请标明出处,谢谢!
这是什么
这是一个在Unity中,用以记录某个代码行为运行时间的小工具。效果如下图所示,它们分别展示了:
- 一次任务的记录
- 嵌套任务的记录(记录中嵌套记录)
- 递归任务的记录(套娃)
为什么要用它
笔者的毕业设计中要时刻关注一些代码行为的时间消耗。如果使用C#的Stopwatch类,会严重破坏代码结构,并且当如果需要记录一个行为中若干子行为各自时间时(例如函数A包含函数AA、AB,我想要记录这三个函数的时间,并直观得到各部分占A的比例),很难通过Stopwatch达到目的。
因此笔者封装了一个用以记录时间消耗的工具,它具有以下特点:
- 简单、安全的使用方式,几乎不破坏代码结构,更不会影响执行结果
- 嵌套记录时,很容易看到一个父行为中各个子行为的时间消耗
- 通过编辑器扩展,无需通过调试、Log输出等方式查看结果
其他
- 因为源码中有一定的注释且代码量少,因此代码讲解部分比较简陋。如果你需要详细的的讲解,请使用私信或者评论的方式告诉我,我会进行补全!
使用方法
我要从哪里获取代码
代码和使用示例已经放在了github上,github地址:
UnknownArkish/UnityTimeRecorder
放在你的工程中:
- 将 Assets/Scripts/TimeRecorder.cs文件放在你的工程目录中放置脚本文件夹的下;
- 将Assets/Editor/TimeRecorderEditor.cs文件放置在你的工程目录的Assets/Editor文件夹下(或Editor中的文件夹,总之目录路径要在Editor中)
- 场景中创建一个物体,挂上 TimeRecorder.cs 脚本
使用示例
TimerRecorder中只有一个关于记录时间的函数 Record,其函数原型如下:
public void Record(
string actionName,
Action action,
RecordUnit unit = RecordUnit.Millisecond
)
- string actionName: 行为的名字;
- Action action: 行为,需要传入一个无参无返回值的函数,也可传入一个 无参无返回值的 lambda表达式;
- RecordUnit unitOption: 可选参数,行为记录的时间单位。
注意:由于TimeRecorder采用单例模式,因此你需要通过 TimeRecorder.Instance 获取单例实例。
简单记录
大多数情况下,你只需要将需要记录的行为打包成一个lambda表达式作为参数传入即可。如下所示将会记录任务A的执行时间:
TimeRecorder.Instance.Record(
"任务A",
()=>{
// 任务A...
}
);
// 任务B...
// 任务C...
更具体的例子,假设有以下两个任务,一个任务几乎不耗时,一个任务耗时严重(方便起见这里使用循环模拟,也可使用协程):
// 模拟一项简单的任务,几乎不消耗时间
private void SimpleFunc() { }
// 模拟一项繁重的任务,消耗很多时间
private void HeavyFunc()
{
int count = 1000000;
for (int i = 0; i < count; i++) { }
}
它们在示例代码中的调用如下:
private void TestSimpleFunc()
{
SimpleFunc();
}
private void TestHeavyFunc()
{
HeavyFunc();
}
如果我想知道SampleFunc(或者HeavyFunc)的执行时间,那么只需要更改为如下所示的代码即可:
private void TestSimpleFunc()
{
TimeRecorder.Instance.Record("TestSimpleFunc", () =>
{
SimpleFunc();
});
}
private void TestHeavyFunc()
{
TimeRecorder.Instance.Record("TestHeavyFunc", () =>
{
HeavyFunc();
});
}
查看记录
行为的记录结果可以在挂载了 TimeRecorder.cs 脚本的 Inspector 窗口上查看。
如下图所示,当示例程序若干次调用 TestSimpleFunc 和 TestHeavyFunc后,在 Inspector 上所观察到的结果:
嵌套记录
和简单记录一样,你只需要在想要记录的行为处调用 TimeRecorder.Instance.Record 代码即可。
- 如果出现了嵌套记录,TimerRecorder会自动处理好它们,你无需担心任何事情。
为了模拟嵌套记录,示例代码中使用了如下代码:
(TestEmbeddedFunc中嵌套了刚才的TestSimpleFunc和TestHeavyFunc)
// 测试嵌套记录
private void TestEmbeddedFunc()
{
TimeRecorder.Instance.Record("EmbeddedFunc", () =>
{
TestSimpleFunc();
TestHeavyFunc();
});
}
运行结果如下图所示,同样的你可以在Inspecotr上查看得到:
- 可以很直观的发现TestSimpleFunc和TestHeavyFunc是TestEmbeddedFunc的子行为,以及它们各自的时间。
递归记录
即便是递归的行为也能正常工作。为了模拟递归,示例代码中使用以下代码:
// 测试递归记录,参数是递归次数
private void TestRecursiveFunc(int recursiveTime)
{
if (recursiveTime < 1) return;
TimeRecorder.Instance.Record(
string.Format("TestRecursiveFunc_{0}", recursiveTime),
() =>
{
HeavyFunc();
TestRecursiveFunc(recursiveTime - 1);
}
);
}
运行结果如下图所示(这里递归次数为5):
代码讲解
由于源代码中已经有一定的注释,而且代码量很少,读者感兴趣的话可以自行阅读:
- 编辑器扩展部分要求读者有相关的编写经验,除非你需要改动源码,可以否则不需要理解这部分(即TimeRecorderEditor.cs)
- 若你对编辑器扩展感兴趣,可以学习这篇文章(原作者分为了三篇文章,这里只给出第一篇):
- https://blog.csdn.net/qq_33337811/article/details/61920340