Unity 协程深入解析与原理

先来直接放一段代码

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 
 5 public class CoroutineTest : MonoBehaviour
 6 {
 7 
 8     void Start()
 9     {
10         Debug.Log("Start Begin");
11 
12         CustomCoroutine = DelayPrint("Hi");
13 
14         Debug.Log("Start End");
15     }
16 
17     bool isStartCoroutine = true;
18     IEnumerator CustomCoroutine = null;
19     void Update()
20     {
21         Debug.Log(""+Time.frameCount+"Update 在执行");
22         if (isStartCoroutine)
23         {
24             if (CustomCoroutine.MoveNext())
25             {
26                 Debug.Log(CustomCoroutine.Current.ToString());
27             }
28         }
29         Debug.Log("" + Time.frameCount + "Update执行结束");
30     }
31 
32     public IEnumerator DelayPrint(string somevalue)
33     {
34         Debug.Log("DelayPrint Start");
35         yield return 0;
36         Debug.Log("DelayPrint Debug:" + somevalue);
37         Debug.Log("DelayPrint End");
38     }
39 
40 }
CoroutineTest

代码结果如下:

这样一看是不是跟我们平时在Unity使用的StartCoroutine基本上是一样的了?其实还是有不一样的地方,这因为在Unity内部对自己的协程管理作了特殊处理(猜测)。

在Unity内的协程位置顺序图如下:

而我们在上面写的自己的协程只会在Update里运行,因为我们在Update里写MoveNext(),若是想在其他地方运行我们的协程就写在其他地方就好~

所以说Unity协程的本质就是Unity内部的轮询机制和IEnumerator迭代保存上下文执行代码段。

而我们平时在协程方法yield return XXX只是把这时刻代码运行的控制权交回给主线程(类似操作系统中的挂起),其他协程或者其他线程(类似WWW类,这会真正开启另一个线程去执行,否则本质上都是单线程),,然后保存当前方法代码段的状态,等Unity内部的再次轮询回到被挂起时的代码状态继续执行,直到没有yield return的时候,这样就形成了一种代码分段执行的效果。

也当只有yield return XXX时IEnumerator.MoveNext()才会为true,然后IEnumerator.Current是yield return XXX的XXX。

所以在Unity里面的yield return WaitForSeconds返回给Unity中内部的协程状态机作判断处理,例如如果是返回WaitForSeconds类则给这个协程求时间差以达到延迟处理。

如果没有yield return,也就是没有返回值,这时IEnumerator.MoveNext()为false,这就会退出了Unity轮询。

大概就这样,要是更想理解细节的话可以百度IEnumerator和作用和把上面的代码逐步调试下即可。

参考:https://www.zhihu.com/question/34878524/answer/61555725

   https://www.zhihu.com/question/23895384/answer/26066323

     http://dsqiu.iteye.com/blog/2029701

     CoroutineManager插件源码(这个插件是在自己的Update方法里不断轮询CoroutineManager的协程集合内,获取每个协程的MoveNext()状态,从而进行一些简单的判断管理一个协程)

posted on 2017-03-16 19:02  爱裸奔的小亮亮  阅读(456)  评论(0编辑  收藏  举报

导航