[U3D][Yield][协程]对U3D开发脚本C#中的协程理解

一、协程是什么

协程不是进程,更不是线程
协程是在主线程中执行的

协程大概的意思是:
协程函数中暂时不执行 yield 后边的代码,返回到调用协程函数的位置继续执行,
当满足 yield 的条件后再执行后边的代码。

协程能当延时器使用,当你理解它的运行逻辑后,也许你能开发出更多、更有效的用法。

二、协程的用法

1、定义的协程函数必须是 IEnumerator 返回类型
2、在协程函数里边至少有一个 yield 语句
3、yield 后边可以有多种条件
4、调用协程函数,必须使用 StartCoroutine() 方法

StartCoroutine(Test());				//调用

IEnumerator Test() {
	//code1
	
	yield return null;				//这里的意思是下一帧再继续执行
	
	yield return new WaitForSeconds(2);	//这里的意思是等待两秒再执行
	
	yield return 其他条件都可;		//虽然其他条件表达式都可以,
									//但是任何真假表达式它都是等待一帧再执行。
									
	//code2
}

其他用法详见:C#协程的用法

三、协程的实验

1、使用 yield return null,并在 Start() 方法中调用;

message.Enqueue(FPSCount.ToString() + ": yield before");
yield return null;
message.Enqueue(FPSCount.ToString() + ": yield after");


可以看到,在第0帧的时候,输出了 before
第2帧输出了after
与预期的不太一样呢,应该间隔一帧
原因是,在Start中调用时,Update还未执行,所以第一帧计数就没有增加
然后就没有输出了,可以知道,这个协程函数只经历了一次函数周期

2、使用 yield return new WaitForSeconds(2); 在Start中

message.Enqueue(FPSCount.ToString() + ": yield before");
yield return new WaitForSeconds(2);
message.Enqueue(FPSCount.ToString() + ": yield after");

输出和上图一致,只不过输出after时,间隔了两秒

3、使用 yield return 条件表达式

message.Enqueue(FPSCount.ToString() + ": yield before");
yield return false;
//yield return true;
message.Enqueue(FPSCount.ToString() + ": yield after");

在Update中;在这里插入图片描述
在Start中

message.Enqueue(FPSCount.ToString() + ": yield before");
yield return false;
//yield return true;
message.Enqueue(FPSCount.ToString() + ": yield after");
StartCoroutine(test());		//加这一句为了抑制调用协程函数


运行出来发现,在Update中,before和after在同一帧,注意,before在after前面。并且,它不关心return后边是真是假,依旧是下一帧执行,以及有文章说yield return num; 为间隔num帧执行,而我测试依旧是间隔一帧,不知道是不是我的写法有问题。

在Start中,before和after不在同一帧。
这里的细节关系到下面讲的,协程运行原理中的协程执行顺序。

这两个例子都会连续每帧输出,原因是,Update会每帧执行,执行时就会每帧都调用协程函数。所以协程函数并不是循环执行的,它只执行一个函数周期,当执行完成后,函数应该就销毁了,也就是yield后的条件满足后并执行完后边代码就销毁了。
而第二个在Start中,只执行了一次,但是,我在最后边加了再次调用本协程函数的方法,所以他会是一个死循环得递归。但是值得注意的是,它并不会卡死程序,因为他在一帧只递归一次。

四、协程的原理(个人理解)

我们都知道,在U3D中,一个脚本都有一个调用顺序,Start在脚本挂起时,只调用一次就不调用了,Update在每帧调用,FixedUpdate每隔0.02秒调用一次,其他的暂不研究。
那么Update和协程有什么联系呢?

协程yield后的代码会在满足条件后执行,所以每一帧都会检测协程的条件,判断它是否满足。
通过上面第3个实验,我推理出了协程可能会在哪里去检测。见下图:

Start
新帧开始
Update
协程检测

首先执行Start,接着执行Update,协程检测应该在Update的后边。

推理方法为假设法

假设协程检测在Update之前:
那么在第一帧,先会检测是否有满足的协程条件,
此时我们还没有开启协程,自然没有任何东西,
然后执行到update,运行到了协程函数,输出了before,并退出,下面的下一帧再执行,
然后新的一帧,检测了协程条件,发现上一帧有个未完成的协程函数,并接着执行,输出after,
然后执行update,又运行协程函数,输出before,并把后面的交给下一帧。
此时帧数和输出对应的是
1:before
2:after
2:before
3:after
3:before
显然与我们实验的不符,见实验3-Update部分,正确的应该是在同一帧,before在前。

接着假设协程检测在Update后
第一帧先执行update,并在内执行协程函数,输出before,
update完后检测协程条件,发现有协程事件,但条件不满足,因为当前在同一帧,
在第二帧,先执行update,执行协程函数,输出before,
完后检测,发现有来个协程事件,其中,满足上一帧的一个事件,则输出after,
以此类推,此时帧数和输出对应的是
1:before
2:before
2:after
3:before
3:after
此时在同一帧,before在after前,符合输出。

以上均为个人理解,不能作为专业解释。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值