必读好文推荐:

Unity协程(Coroutine)原理深入剖析

Unity协程(Coroutine)原理深入剖析再续

上面的文章说得太透彻,所以这里就记一下自己的学习笔记了。

首先要说明的是,协程并不是线程,协程是运行在主线程中的,是和主线程同步执行的代码,不同的地方是运行的方法可以被yield return在当前帧进行打断,到下一帧后可以继续从被打断的地方继续运行。

下面我们看一个示例,场景中有一个空的GameObject对象,其绑定了下面的脚本:

  1. 1 using UnityEngine;
  2. 2 using System.Collections;
  3. 3
  4. 4 public class Test : MonoBehaviour
  5. 5 {
  6. 6 int frame = 0;
  7. 7
  8. 8 void Start ()
  9. 9 {
  10. 10 this.StartCoroutine(CountDown());
  11. 11 }
  12. 12
  13. 13 void Update ()
  14. 14 {
  15. 15 Debug.Log("Now is frame: " + (++frame));
  16. 16 }
  17. 17
  18. 18 IEnumerator CountDown()
  19. 19 {
  20. 20 Debug.Log("step - 1");
  21. 21 yield return null;
  22. 22 Debug.Log("step - 2");
  23. 23 yield return null;
  24. 24 Debug.Log("step - 3");
  25. 25 yield return null;
  26. 26 Debug.Log("step - 4");
  27. 27 }
  28. 28 }

下面是执行的结果:

下面我们看看运行的逻辑是如何的:

当进入Start方法时开始启动协程,这时候协程开始运行,输出“step1”后遇到第一个yield return后暂停本帧的运行,接下来进入Update方法输出“frame1”,由于协程调用是在Update之后,所以第二帧开始后,先执行了第二个Update输出“frame2”,然后从协程的上次暂停处继续执行,输出“step2”后遇到第二个yield return后暂停本帧的运行,如此反复,当输出“step4”后发现方法已经执行完毕,协程结束。

下面看看yield break的效果,这个语句会立即中断协程的运行,代码如下:

  1. 1 using UnityEngine;
  2. 2 using System.Collections;
  3. 3
  4. 4 public class Test : MonoBehaviour
  5. 5 {
  6. 6 int frame = 0;
  7. 7
  8. 8 void Start ()
  9. 9 {
  10. 10 this.StartCoroutine(CountDown());
  11. 11 }
  12. 12
  13. 13 void Update ()
  14. 14 {
  15. 15 Debug.Log("Now is frame: " + (++frame));
  16. 16 }
  17. 17
  18. 18 IEnumerator CountDown()
  19. 19 {
  20. 20 Debug.Log("step - 1");
  21. 21 yield return null;
  22. 22 Debug.Log("step - 2");
  23. 23 yield return null;
  24. 24 Debug.Log("step - 3");
  25. 25 yield break;
  26. 26 Debug.Log("step - 4");
  27. 27 }
  28. 28 }

下面是运行的结果:

我们可以发现“step4”已经运行不到了。

yield的返回值,我们可以返回null或者数字0,效果是一致的,同时还可以返回3个对象,分别如下:

  1. yield return new WaitForFixedUpdate();

·等待直到下一个固定帧速率更新函数。

  1. yield return new WaitForEndOfFrame();

·等待直到所有的摄像机和GUI被渲染完成后,在该帧显示在屏幕之前。

  1. yield return new WaitForSeconds(1);

·在给定的秒数内,暂停协同程序的执行。

下面我们来看一个例子,修改第一个例子的Test.cs:

  1. 1 using UnityEngine;
  2. 2 using System.Collections;
  3. 3
  4. 4 public class Test : MonoBehaviour
  5. 5 {
  6. 6 int frame1 = 0;
  7. 7 int frame2 = 0;
  8. 8 int frame3 = 0;
  9. 9
  10. 10 void Start ()
  11. 11 {
  12. 12 this.StartCoroutine(CountDown());
  13. 13 this.StartCoroutine(CountDown_WaitForFixedUpdate());
  14. 14 this.StartCoroutine(CountDown_WaitForEndOfFrame());
  15. 15 this.StartCoroutine(CountDown_WaitForSeconds());
  16. 16 }
  17. 17
  18. 18 void Update ()
  19. 19 {
  20. 20 Debug.Log("Update is frame: " + (++frame1));
  21. 21 }
  22. 22
  23. 23 void FixedUpdate ()
  24. 24 {
  25. 25 Debug.Log("FixedUpdate is frame: " + (++frame2));
  26. 26 }
  27. 27
  28. 28 void LateUpdate ()
  29. 29 {
  30. 30 Debug.Log("LateUpdate is frame: " + (++frame3));
  31. 31 }
  32. 32
  33. 33 IEnumerator CountDown()
  34. 34 {
  35. 35 Debug.Log("yield - step - 1");
  36. 36 yield return null;
  37. 37 Debug.Log("yield - step - 2");
  38. 38 yield return null;
  39. 39 Debug.Log("yield - step - 3");
  40. 40 }
  41. 41
  42. 42 IEnumerator CountDown_WaitForFixedUpdate()
  43. 43 {
  44. 44 Debug.Log("yield WaitForFixedUpdate - step - 1");
  45. 45 yield return new WaitForFixedUpdate();
  46. 46 Debug.Log("yield WaitForFixedUpdate - step - 2");
  47. 47 yield return new WaitForFixedUpdate();
  48. 48 Debug.Log("yield WaitForFixedUpdate - step - 3");
  49. 49 }
  50. 50
  51. 51 IEnumerator CountDown_WaitForEndOfFrame()
  52. 52 {
  53. 53 Debug.Log("yield WaitForEndOfFrame - step - 1");
  54. 54 yield return new WaitForEndOfFrame();
  55. 55 Debug.Log("yield WaitForEndOfFrame - step - 2");
  56. 56 yield return new WaitForEndOfFrame();
  57. 57 Debug.Log("yield WaitForEndOfFrame - step - 3");
  58. 58 }
  59. 59
  60. 60 IEnumerator CountDown_WaitForSeconds()
  61. 61 {
  62. 62 Debug.Log("yield WaitForSeconds - step - 1");
  63. 63 yield return new WaitForSeconds(1 / 60 * 3);//大概是三帧的时间
  64. 64 Debug.Log("yield WaitForSeconds - step - 2");
  65. 65 yield return new WaitForSeconds(1 / 60 * 3);
  66. 66 Debug.Log("yield WaitForSeconds - step - 3");
  67. 67 }
  68. 68 }

运行的结果如下,有点长,我就弄成两张图了:

通过输出我们可以得出下面的结果:

  1. 当帧数波动时,FixedUpdate会进行多次补帧处理,我们可以发现两张图之间FixedUpdate从3一直补帧到15;
  2. WaitForFixedUpdate表示协程是跟在FixedUpdate之后执行的;
  3. WaitForEndOfFrame表示协程是跟在LateUpdate之后执行的;
  4. WaitForSeconds额。。。不用多说了,你指定多久后执行就多久后执行,当然由于是基于帧运算的,所以可能会不准确;

最后补一张开头博客的运行顺序图:

天道酬勤,功不唐捐!

yield学习续:yield return迭代块在Unity3D中的应用——协程的更多相关文章

  1. 学习PYTHON之路, DAY 10 进程、线程、协程篇

    线程 线程是应用程序中工作的最小单元.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 直接调用 impo ...

  2. Python学习笔记整理总结【网络编程】【线程/进程/协程/IO多路模型/select/poll/epoll/selector】

    一.socket(单链接) 1.socket:应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socke ...

  3. php yield关键字以及协程的实现

    php的yield是在php5.5版本就出来了,而在初级php界却很少有人提起,我就说说个人对php yield的理解 Iterator接口 在php中,除了数组,对象可以被foreach遍历之外,还 ...

  4. 再议Python协程——从yield到asyncio

    协程,英文名Coroutine.前面介绍Python的多线程,以及用多线程实现并发(参见这篇文章[浅析Python多线程]),今天介绍的协程也是常用的并发手段.本篇主要内容包含:协程的基本概念.协程库 ...

  5. (转)python协程2:yield from 从入门到精通

    原文:http://blog.gusibi.com/post/python-coroutine-yield-from/ https://mp.weixin.qq.com/s?__biz=MzAwNjI ...

  6. python协程--yield和yield from

    字典为动词“to yield”给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来说,这两个含义都成立.yield item 这行代码会产出一个值,提供给 next(...) 的 ...

  7. Python异步IO之协程(一):从yield from到async的使用

    引言:协程(coroutine)是Python中一直较为难理解的知识,但其在多任务协作中体现的效率又极为的突出.众所周知,Python中执行多任务还可以通过多进程或一个进程中的多线程来执行,但两者之中 ...

  8. 【Python】【容器 | 迭代对象 | 迭代器 | 生成器 | 生成器表达式 | 协程 | 期物 | 任务】

    Python 的 asyncio 类似于 C++ 的 Boost.Asio. 所谓「异步 IO」,就是你发起一个 IO 操作,却不用等它结束,你可以继续做其他事情,当它结束时,你会得到通知. Asyn ...

  9. 流畅python学习笔记:第十六章:协程

    通常在python进行编程一般都是使用多线程或者多进程来实现.这里介绍另外一种并发的方式,就是协程,但和多线程以及多进程不一样的是,协程是运行在单线程当中的并发.来看下具体的例子: def simpl ...

随机推荐

  1. Android UI 绘制过程浅析(三)layout过程

    前言 上一篇blog中,了解到measure过程对View进行了测量,得到measuredWidth/measuredHeight.对于ViewGroup,则计算出全部children的宽高进行求和. ...

  2. 学习了一下javascript的模块化编程

    现在在我脑海里关于“模块化”的概念是这些词:简单.具有逻辑之美.易用.健壮.可扩展.似乎这些形容与我现在水平写出的代码有点格格不入啊. 所以今天想了解和简单的实践一下“模块化开发”. 1.首先学习一下 ...

  3. LoadRunner使用技巧之添加事务

    事务(Transaction)用于模拟用户的一个相对完整的.有意义的业务操作过程,例如登录.查询.交易.转账,这些都可以作为事务,而一般不会把每次HTTP请求作为一个事务. 以刚刚过去的双11淘宝为例 ...

  4. oracle创建包后执行报错:object omgmig.test_package is invalid.

    今天学习了一下oracle的包的写法,然后碰到这么个问题.包声明和包主体都正确,但是就是执行报错:object omgmig.test_package is invalid. 这是会报错的sql,看起 ...

  5. DEDE后台添加新变量出现:Request var not allow!的解决办法 相关案例演

    论坛上很多人都反馈说在后台添加新变量的时候会出现 "Request var not allow!" 的BUG错误,本文主要就是介绍如何去解决这个问题!下面看具体操纵:在DEDE根目 ...

  6. form 编译命令

    11i: Form:f60gen $AU_TOP/forms/ZHT/GLXJEENT.fmb userid=apps/tpsadbm output_file=$GL_TOP/forms/ZHT/GL ...

  7. 交换两个数-c++实现

    今天看了下交换数值的小程序,网上挺多的,整理了下,,因为参考较多,没一一给出链接,若原作者看到,可以留言,我会添加 // example_1_6_function_swap.cpp : 定义控制台应用 ...

  8. set QUOTED_IDENTIFIER ON事故记录

    作业执行失败: 看了一下执行脚本 delete  top(8000) from "interface"."完成" where  loggid in( selec ...

  9. 《C++编程规范:101条规则、准则与最佳实践》学习笔记

    转载:http://dsqiu.iteye.com/blog/1688217 组织和策略问题 0. 不要为小事斤斤计较.(或者说是:知道什么东西不需要标准化) 无需在多个项目或者整个公司范围内强制实施 ...

  10. HowTo Perform the spatial selection 'Share a line segment with' using ArcObjects

    HowTo  Perform the spatial selection 'Share a line segment with' using ArcObjects Article ID: 26528 ...