协程的使用场景
对于保证不会阻塞的并行操作且并行性要求不高的并行操作,可以使用协程。
更实际来说,协程最常用于延时执行等控制时间轴的操作,例如N秒后调用指定函数。
利用每帧执行一段协程的特性,我们可以引入个带累加计时判断循环,然后再超过3秒后跳出循环,执行Debug.Log()
//3s后执行Debug.Log
IEnumerator Test()
{
for(float timer = 0.0f; timer < 3.0f ; timer += Time.DeltaTime){
yield return 0;//挂起,下一帧再来从这个位置继续执行。
}
Debug.Log("启动协程3s后");
}
但是Unity封装了个更好用的类:WaitForSeconds
使这种延时的协程代码更加简洁。
//原本写法
for(float timer = 0.0f; timer < 3.0f ; timer += Time.DeltaTime){
yield return 0;//挂起,下一帧再来从这个位置继续执行。
}
//使用WaitForSeconds的写法
yield return new WaitForSeconds(3.0f);
协程使用示例
接下来就展示下,协程使用的示例:
首先编写好协程函数
IEnumerator TestWaitForSeconds()
{
//3s后执行Debug.Log;
yield return new WaitForSeconds(3.0f);
Debug.Log("启动协程3s后");
}
然后在某个地方使用StartCoroutine(TestWaitForSeconds())或者StartCoroutine("TestWaitForSeconds")
//启动协程:3s后执行Debug.log
StartCoroutine(TestWaitForSeconds());
//启动后,继续往下执行
...
Invoke的缺陷
另外一提,Unity还有个一样也是用于延时调用的函数,叫Invoke
Invoke("test",2.0f); \\延时2秒后执行函数test
但是Invock所要调用的函数必须是空类型返还值,还必须得是在当前类里面的方法。
一般来说,用协程来解决这样的问题已经绰绰有余,而且还有更安全的调用方法而不是只用string类型作为参数的方法,因此没必要使用Invoke。
协程语法
开启协程
StartCoroutine(string methodName);
- 参数是方法名(字符串类型),此方法可以包含一个参数。
- 形参方法可以有返回值
StartCoroutine(IEnumerator method);
- 参数是方法(TestMethod()),此方法中可以包含多个参数。
- IEnumrator类型的方法不能含有ref或者out类型的参数,但可以含有被传递的引用
- 形参方法必须有返回值,且返回值类型为IEnumrator,返回值使用(yield retuen +表达式或者值,或者 yield break)语句
终止协程
StopCoroutine(string methodName);//终止指定的协程
- 在程序中调用StopCoroutine()方法只能终止以字符串形式启动的协程
StopAllCoroutine();//终止所有协程
挂起
//程序在下一帧中从当前位置继续执行
yield return 0;
//程序在下一帧中从当前位置继续执行
yield return null;
//程序等待N秒后从当前位置继续执行
yield return new WaitForSeconds(N);
//在所有的渲染以及GUI程序执行完成后从当前位置继续执行
yield new WaitForEndOfFrame();
//所有脚本中的FixedUpdate()函数都被执行后从当前位置继续执行
yield new WaitForFixedUpdate();
//等待一个网络请求完成后从当前位置继续执行
yield return WWW;
//等待一个xxx的协程执行完成后从当前位置继续执行
yield return StartCoroutine(xxx);
//如果使用yield break语句,将会导致协程的执行条件不被满足,不会从当前的位置继续执行程序,而是直接从当前位置跳出函数体,回到函数的根部
yield break;
协程的执行原理
协程函数的返回值时IEnumerator,它是一个迭代器,可以把它当成执行一个序列的某个节点的指针。
它提供了两个重要的接口,分别是Current(返回当前指向的元素)和MoveNext()(将指针向后移动一个单位,如果移动成功,则返回true)。
yield关键词用来声明序列中的下一个值或者是一个无意义的值。
如果使用yield return x(x是指一个具体的对象或者数值)的话,
那么MoveNext返回为true并且Current被赋值为x,如果使用yield break使得MoveNext()返回为false。
如果MoveNext函数返回为true意味着协程的执行条件被满足,则能够从当前的位置继续往下执行。否则不能从当前位置继续往下执行。