简介
之前的项目,无意中发现一个现象,虽然不影响程序与代码,但也在这里记录分享一下。
代码
先上代码:
using System.Collections;
using UnityEngine;
using UnityEngine.Profiling;
public class Test : MonoBehaviour
{
public static Test Instance;
void Awake()
{
DontDestroyOnLoad(Instance = this);
}
void Start()
{
StartCoroutine(test01());
StartCoroutine(test02());
StopAllCoroutines();
}
void Update()
{
StartCoroutine(test03());
}
private IEnumerator test01()
{
Debug.Log("test01");
yield return null;
StopCoroutine(test01());
}
private IEnumerator test02()
{
while (true)
{
Profiler.BeginSample("test02");
Debug.Log("test02");
Profiler.EndSample();
yield return new WaitForEndOfFrame();
}
}
private IEnumerator test03()
{
Profiler.BeginSample("test03");
Debug.Log("test03");
Profiler.EndSample();
yield return null;
}
}
Debug
上面的代码并不难,应该都能知道会出现什么效果。
效果如图,没有什么特别的。
Profiler
关键在于Profiler中的显示,代码引用了UnityEngine.Profiling的代码库,并在代码中调用了两次Profiler.BeginSample函数,用于现实效果。
我们从代码可以知道,test01协程函数只在最开始运行了一次,之后便是在Update函数中反复调用的test03协程函数一直在运行。可是从Profiler界面中,可以发现test03的Profiler.BeginSample函数却显示在test01的协程Coroutine的下面,而test01的Coroutine显示的状态为MoveNext,test03的Coroutine显示的状态为System.Collections.IEnumerator.get_Current。
现象
经过我的多次测试,发现无论怎要的触发协程,其正在运行协程的Profiler(包括耗时,GC等),都会显示在以程序第一个运行的协程命名的状态显示为MoveNext的Coroutine之下;而以正在运行的协程命名的Coroutine,只会显示System.Collections.IEnumerator.get_Current的状态。
结论
这个对于我们的程序不会有任何的影响,但能帮助我们更好的了解Unity的协程机制。
我们都知道,协程是一个类似多线程的机制,但其本质上还是单线程。再结合以上现象,我便有了以下的一个理解(也可是说是一个猜测,不一定正确,只是帮助大家更好的理解协程)。
其中Profiler界面中以协程命名的Coroutine,我理解为一个指针(C#中没有指针,C#中与其类似的是委托和事件,就是一个用于指向一个贮存属性或函数的物理地址的属性),每一个协程在程序中都会生成一个以其命名的指针,但真正用到的却只是程序运行时第一个运行的协程所创建的指针,该指针指向正在执行协程,在Profiler界面其协程所占用的损耗,也就完全归于这个第一个运行的协程指针。