1.协程
协程其实就是一个IEnumerator(迭代器),
IEnumerator 接口有两个方法 Current 和 MoveNext()
Unity在每一帧做的事情是:调用协程(迭代器)MoveNext()方法,如果返回true,则从当前位置继续执行。
什么是协程?
协同程序,即在主程序运行时,同时启动另一段逻辑处理,以协同当前程序的执行。也就是说,启动一个协程就是启动一个线程。
协程是部分执行。当遇到条件(yield return语句)时3D角色,会被挂起,直到满足条件后才会被唤醒,继续执行后面的代码。通俗地说:程序可以在里面中断unity 协程和线程区别,然后转而去执行其他的子程序,在合适的时候再返回继续执行。
协程的运行
协程不是线程,也不是异步执行的。协程也像MonoBehaviour的Update函数一样在MainThread中执行。
协程可以与主程序并行运行,类似于多线程。
协程的作用
1.延迟(等待)一段时间执行代码;
2. 在执行以下代码之前等待操作完成。
一句话概括就是:控制代码在特定的时间执行。
粘贴图片.png
WaitForSeconds()受Time.timeScale的影响,当Time.timeScale = 0f时,yield return new WaitForSecond(x)不会被满足。
练习测试
void Start () {
print("开始下载" + "---" + Time.time);
StartCoroutine(waitOne());
print("正在下载----50%" + "---" + Time.time);
}
IEnumerator waitOne()
{
Debug.Log("加入下载列表" + "---" + Time.time);
yield return StartCoroutine(waitTwo());
print("下载完成" + "---" + Time.time);
}
IEnumerator waitTwo()
{
print("正在下载----1%" + "---" + Time.time);
yield return new WaitForSeconds(3);
print("正在下载----70%" + "---" + Time.time);
}
打印结果(执行顺序):
粘贴图片.png
脚本协程禁用后还会执行吗?
粘贴图片.png
2.WaitUntil和WaitWhile的秘密
开始学习 WaitUntil:
θ 根据定义,它暂停语句直到指定的条件返回 true。
θ 换句话说,当我们指定的条件为假时,它不会继续执行语句。Unity 将等待条件返回真。
测试
public int counter;
void Start ()
{
counter = 0;
StartCoroutine(FuelNotification());
}
IEnumerator FuelNotification()
{
Debug.Log("开始通关" + "---" + Time.time);
yield return new WaitUntil(IsTankEmpty);
Debug.Log("通关了!" + "---" + Time.time);
}
void Update()
{
if (counter<21)
{
Debug.Log("通关数量:"+counter+"---"+Time.time);
counter++;
}
}
public bool IsTankEmpty()
{
if (counter<21)
{
return false;
}
else
{
return true;
}
}
打印结果:
粘贴图片.png
让我们来看看如何使用 Lambda 表达式。Lambda 表达式是一个非常方便的工具,试试吧。
public int counter;
void Start()
{
counter = 20;
StartCoroutine(FuelNotification());
}
void Update()
{
if (counter > 0)
{
Debug.Log("Fuel Level:" + counter + "---" + Time.time);
counter--;
}
}
IEnumerator FuelNotification()
{
Debug.Log("Waiting for tank to get empty" + "---" + Time.time);
yield return new WaitUntil(() => counter <= 0);
Debug.Log("Tank Empty!" + "---" + Time.time);
}
打印结果:
粘贴图片.png
现在了解 WaitWhile:WaitWhile 与 WaitUntil 相反。当条件为真时,它会抑制表达式。与 WaitUntil 不同的是,它会等到条件变为 false 之后再指向后面的代码块。和之前一样的例子,我们使用了WaitWhile:我们只需要将Lambda表达式改为equal False,打印出来的结果是一样的。
public int counter;
void Start()
{
counter = 20;
StartCoroutine(FuelNotification());
}
void Update()
{
if (counter > 0)
{
Debug.Log("Fuel Level:" + counter + "---" + Time.time);
counter--;
}
}
IEnumerator FuelNotification()
{
Debug.Log("Waiting for tank to get empty" + "---" + Time.time);
yield return new WaitUntil(() => counter > 0);
Debug.Log("Tank Empty!" + "---" + Time.time);
}
图片.png
3.线程和协程的区别
线
线程间共享变量解决了通信麻烦的问题,但是变量的访问需要锁,线程的调度主要由操作系统来完成。一个进程可以有多个线程,但是每个线程都会共享父进程来操作系统申请的资源,包括虚拟内存、文件等,由于是共享资源unity 协程和线程区别,所以创建一个线程需要的系统资源要小很多相比进程,相应的可以创建的线程数也变得比较大。除了进程间的通信,线程时的通信还可以通过共享内存进行通信,所以这个速度比通过内核要快很多。另外在调度方面,因为内存是共享的,
协程
协程的调度完全由用户控制。一个线程可以有多个协程。用户创建若干个线程音效,然后每个线程按照指定的任务列表顺序循环完成不同的任务,当任务被阻塞时执行。当下一个任务恢复时,回来执行这个任务。任务之间的切换只需要保存每个任务的上下文内容,就像直接操作栈一样,这样完全没有内核切换的开销,也不需要锁。访问全局变量,所以上下文切换非常快;另外,协程需要保证是非阻塞的,没有相互依赖。协程基本不能同步通信,多使用一步的消息通信,效率更高。