StartCoroutine在unity3d的帮助中叫做协程,意思就是启动一个辅助的线程。
在C#中直接有Thread这个线程,但是在unity中有些元素是不能操作的。这个时候可以使用协程来完成。
使用线程的好处就是不会出现界面卡死的情况,如果有一次非常大量的运算,没用线程就会出现假死的情况。
下面通过一个简单的例子来说明使用协程的好处:
1. void OnGUI()
2. {
3. new Rect(0, 0, 200, 50), "测试1:" + result);
4. if (GUI.Button(new Rect(0, 100, 100, 50), "开启协程"))
5. {
6. StartCoroutine(GetResult());
7. }
8.
9. new Rect(200, 0, 200, 50), "测试2:" + result1);
10. if (GUI.Button(new Rect(200, 100, 100, 50), "无协程测试"))
11. {
12. GetResult1();
13. }
14. }
上面的代码表示在GUI中定义2个label和按钮,一个按钮启动协程计算,另一个直接计算结果。由于2个方法都是计算同样的结果,计算量比较大,所以直接计算出现了暂时的卡死情况。
1. float result;
2. IEnumerator GetResult()
3. {
4. for (int i = 0; i < 1000; i++)
5. {
6. for (int j = 0; j < 100000; j++)
7. {
8. result += (i + j);
9.
10. }
11. if(i%100==0)
12. return 1;
13.
14. }
15. }
这个方法是协程的写法,在C#中协程要定义为IEnumerator 这个类型,javascript中不需要。
yield return 1;这句话表示返回1帧的结果。在i为100的整数时,就返回一次结果,这样可以避免大量的计算卡死。
1. float result1;
2. void GetResult1()
3. {
4. for (int i = 0; i < 1000; i++)
5. {
6. for (int j = 0; j < 100000; j++)
7. {
8. result1 += (i + j);
9. }
10. }
11. }
这个方法就是直接计算结果,由于运算量比较大,所以界面会卡死,这样就可以体现出用协程的好处了。
使用IEnumerator 这个类型时,必须用yield return来返回结果,参数为数字时表示为帧数。
如yield return 1 表示每一帧返回一次结果。
我在这摘要下:
1.
coroutine,中文翻译“协程”。这个概念可能有点冷门,不过百度之,说是一种很古老的编程模型了,以前的操作系统里进程调度里用到过,现在操作系统的进程调度都是根据时间片和优先级来进行轮换,以前是要程序自己来释放cpu的控制权,一直不释放一直也就占用着cpu,这种要求程序自己来进行调度的编程模型应该就叫“协程”了。
协程和线程差不多,线程的调度是由操作系统完成的,协程把这项任务交给了程序员自己实现,当然也就可以提高灵活性,另外协程的开销比线程要小,在程序里可以开更多的协程。
一些语言里自带了对coroutine的实现,比如lua。c里面虽然没有coroutine,不过windows下提供了一种叫fiber的机制,叫做“纤程”,算是一种轻量级线程。
2.
一。什么是协同程序
协同程序,即在主程序运行时同时开启另一段逻辑处理,来协同当前程序的执行。换句话说,开启协同程序就是开启一个线程。
二。协同程序的开启与终止
在Unity3D中,使用MonoBehaviour.StartCoroutine方法即可开启一个协同程序,也就是说该方法必须在MonoBehaviour或继承于MonoBehaviour的类中调用。
在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启一个线程。区别在于使用字符串作为参数可以开启线程并在线程结束前终止线程,相反使用IEnumerator 作为参数只能等待线程的结束而不能随时终止(除非使用StopAllCoroutines()方法);另外使用字符串作为参数时,开启线程时最多只能传递一个参数,并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制。
在Unity3D中,使用StopCoroutine(string methodName)来终止一个协同程序,使用StopAllCoroutines()来终止所有可以终止的协同程序,但这两个方法都只能终止该MonoBehaviour中的协同程序。
还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;如是将协同程序所在脚本的enabled设置为false则不会生效。这是因为协同程序被开启后作为一个线程在运行,而MonoBehaviour也是一个线程,他们成为互不干扰的模块,除非代码中用调用,他们共同作用于同一个对象,只有当对象不可见才能同时终止这两个线程。然而,为了管理我们额外开启的线程,Unity3D将协同程序的调用放在了MonoBehaviour中,这样我们在编程时就可以方便的调用指定脚本中的协同程序,而不是无法去管理,特别是对于只根据方法名来判断线程的方式在多人开发中很容易出错,这样的设计保证了对象、脚本的条理化管理,并防止了重名。
Unity3D之协程(Coroutines & Yield )
这有些个国外的人解释的,算是比较清楚,只是还是没有原理上的解释:
我的一些粗浅小结:
1.Coroutines顾名思议是用来协助主要进程的,在Unity中感觉就是一个可动态添加和移除的Update()函数。它的调用在所有Update函数之后。
Unity原文:
- If you start a coroutine in LateUpdate it will also be called after LateUpdate just before rendering.
- Coroutines are executed after all Update functions.
2.yield就像是一个红绿灯,在满足紧跟在它后面的条件之前,这个协程会挂起,把执行权交给调用它的父函数,满足条件时就可以执行yield下面的代码。
Unity原文:
Coroutine
Normal coroutine updates are run after the Update function returns. A coroutine is function that can suspend its execution (yield) until the given given YieldInstruction finishes. Different uses of Coroutines:
- yield;The coroutine will continue after all Update functions have been called on the next frame.
- yield WaitForSeconds(2);Continue after a specified time delay, after all Update functions have been called for the frame
- yield WaitForFixedUpdate();Continue after all FixedUpdate has been called on all scripts
- yield WWWContinue after a WWW download has completed.
- yield StartCoroutine(MyFunc); Chains the coroutine, and will wait for the MyFunc coroutine to complete first.