协程:在主程序运行的同时,开启另外一段逻辑处理,来协助主程序的执行。
协程的优点:能够分散主程序的计算压力,提高计算时长优化效率
协程的缺点:协程的本质是迭代器,是基于unity的生命周期的,大量的开启协程会引起GC,如果同时激活的协程较多,多个高开销的协程在同一帧执行导致卡顿。
协程函数:
IEnumerator Test()
{
Debug.Log("开始");
yield return new WaitForSeconds(5f);
Debug.Log("已经开始了5s了");
}
IEnumerator Test(float timer)
{
Debug.Log("开始");
yield return new WaitForSeconds(timer);
Debug.Log($"已经开始了{timer}了");
}
调用协程:
private void Start()
{
//调用无参数的协程
StartCoroutine(Test());
StartCoroutine("Test");
//调用有参数的协程
StartCoroutine(Test(5.5f));
StartCoroutine("Test",5.5f);
}
终止协程:
//注意:当想停止某个协程时,开启与停止协程需要使用相同的形式,不可混合使用!
//记录协程并停止协程
Coroutine mCoroutine = null;
void Start()
{
mCoroutine= StartCoroutine(Test());
}
void Stop()
{
//如果开启协程时,用的是字符串(只能终止开启协程时以字符串为参数的协程)
StopCoroutine("Test");
//如果开启协程时,用的是函数名(只能终止开启协程时以函数名为参数的协程)
StopCoroutine(Test());
//以Coroutine为参数终止协程
StopCoroutine(mCoroutine);
}
协程的优化:在协程中直接new一个中断指令,带来不必要的 GC 负担,可以使用一个全局的中断指令来优化
//全局中断指令
WaitForSeconds waitForSeconds = new WaitForSeconds(5f);
void Start()
{
StartCoroutine(Test());
}
IEnumerator Test()
{
Debug.Log("开始");
yield return waitForSeconds;
Debug.Log("已经开始了5s了");
}
协程中yield的用法:
//等待指定时间后执行(1S)
yield return new WaitForSeconds(1f);
//在FixedUpdate结束后再执行
yield return new WaitForFixedUpdate();
//在每帧结束后执行下面的
yield return new WaitForEndOfFrame();
//在指定协程执行后执行下面的
IEnumerator WaitTest()
{
//等待某个协程执行完毕后再执行后续代码
yield return StartCoroutine(Test());
Debug.Log("Good!");
}
//下一帧再执行下面的代码
IEnumerator WaitTest()
{
//下一帧再执行下面的代码
yield return null;
Debug.Log("Good!");
//下一帧再执行下面的代码
yield return 0;//这里可以填任意数字
Debug.Log("haha!");
}
//直接结束协程的接下来的操作
yield break;
对Unity协程的理解:协程不是线程,协程的实现原理是迭代器,迭代器的实现原理是状态机。
Unity中协程执行过程中,通过yield return......将程序挂起执行接下来的内容。在遇到yield return......语句之前,协程方法和一般的方法是相同的,也就是程序在执行到yield return......语句之后,接着才会执行的是StartCoroutine0方法之后的程序,走的还是单线程模式,仅仅是将yield return......语句之后的内容暂时挂起,等到特定的时间才执行。那么挂起的程序什么时候执行呢?协同程序主要是Update0方法之后,LateUpdate0方法之前调用的。通过设置MonoBehaviour脚本的enabled对协程是没有影响的,但如果是设置gameObject.SetActive(false)则已经启动的协程则完全停止了,即使在Inspector把gameObject激活还是没有继续执行。也就说协程虽然是在MonoBehaviour启动的(StartCoroutine) ,但是协程函数的地位完全是跟MonoBehaviour是一个层次的,不受MonoBehaviour的状态影响,但是跟MonoBehaviour脚本一样受gameObject控制,也应该是和MonoBehaviour脚本一样每帧轮询yield的条件是否满足。
Unity3D的协程和C#的线程之间的区别:多线程程序同时运行多个线程,而在任一指定时刻只有一个协程在运行,并且这个正在运行的协同程序只在必要时才被挂起。除主线程之外的线程无法访问Unity3D的对象、组件、方法。Unity3d没有多线程的概念,不过unity也给我们提供了StartCoroutine (协同程序)和LoadLevelAsync(异步加载关卡)后台加载场景的方法。StartCoroutine为什么叫协同程序呢, 所谓协同,就是当你在StartCoroutine的函数体里处理一段代码时, 利用yield语句等待执行结果,这期间不影响主程序的继续执行,可以协同工作。