Unity协程原理、与线程的区别
来源:互联网 发布:医药大数据 编辑:程序博客网 时间:2024/06/13 20:34
参考链接:尘世喧嚣unity 协程原理与线程的区别 http://blog.csdn.net/u011484013/article/details/51136780,本文有个人修改,请点击连接查看原文,尊重楼主版权。
Unity协程
在操作系统(os)级别,有进程(process)和线程(thread)两个我们看不到但又实际存在的“东西”,这两个东西都是用来模拟“并行”的,写操作系统的程序员通过用一定的策略给不同的进程和线程分配CPU计算资源,来让用户“以为”几个不同的事情在“同时”进行“。在单CPU上,是os代码强制把一个进程或者线程挂起,换成另外一个来计算,所以,实际上是串行的,只是“概念上的并行”。在现在的多核的cpu上,线程可能是“真正并行的”。
线程、进程、协程的区别
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。
协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。
打个比方吧,假设有一个操作系统,是单核的,系统上没有其他的程序需要运行,有两个线程 A 和 B ,A 和 B 在单独运行时都需要 10 秒来完成自己的任务,而且任务都是运算操作,A B 之间也没有竞争和共享数据的问题。现在 A B 两个线程并行,操作系统会不停的在 A B 两个线程之间切换,达到一种伪并行的效果,假设切换的频率是每秒一次,切换的成本是 0.1 秒(主要是栈切换),总共需要 20 + 19 * 0.1 = 21.9 秒。如果使用协程的方式,可以先运行协程 A ,A 结束的时候让位给协程 B ,只发生一次切换,总时间是 20 + 1 * 0.1 = 20.1 秒。如果系统是双核的,而且线程是标准线程,那么 A B 两个线程就可以真并行,总时间只需要 10 秒,而协程的方案仍然需要 20.1 秒。
Unity协程执行原理
unity中协程执行过程中,通过yield return XXX,将程序挂起,去执行接下来的内容,注意协程不是线程,在为遇到yield return XXX语句之前,协程的方法和一般的方法是相同的,也就是程序在执行到yield return XXX语句之后,接着才会执行的是 StartCoroutine()方法之后的程序,走的还是单线程模式,仅仅是将yield return XXX语句之后的内容暂时挂起,等到特定的时间才执行。
那么挂起的程序什么时候才执行,这就要看monoBehavior的生命周期了。
也就是协同程序主要是Update()方法之后,LateUpdate()方法之前调用的,
接下来我们通过几个小例子去理解一下。
1/ yield return new WaitForSeconds(1)
using UnityEngine;using System.Collections;using System.Threading;public class test : MonoBehaviour{ void Start() { StartCoroutine(tt());//开启协程 for (int i = 0; i < 200; i++) //循环A { Debug.Log("*************************" + i); Thread.Sleep(10); } } IEnumerator tt() { for (int i = 0; i < 100; i++) //循环B { Debug.Log("-------------------" + i); } yield return new WaitForSeconds(1); //协程1 for (int i = 0; i < 100; i++) //循环C { Debug.Log(">>>>>>>>>>>>>>>>>>>>" + i); yield return null; //协程1 } } // 更新数据 void Update() { Debug.Log("Update"); } //晚于更新 void LateUpdate() { Debug.Log("------LateUpdate"); }}程序的运行结果为:
先执行循环B,然后执行循环A,然后执行当前帧的update()和lateUpdate()的方法,等待1S之后,在update()和lateupdate()之间执行循环C的输出。
2/ 若将上述等待一秒改为yield return null等待1帧,则:
循环B结束后,协程挂起等待下一帧;然后执行循环A,然后当前帧的update,lateupdate;之后在下一帧的update和lateupdate之间执行yield return null后的内容。后面同样道理。
3/ 再改为StartCoroutine
void Start() { StartCoroutine(tt());//开启协程 for (int i = 0; i < 200; i++) //循环A { UnityEngine.Debug.Log("*************************" + i); Thread.Sleep(10); } } IEnumerator tt() { for (int i = 0; i < 100; i++) //循环B { UnityEngine.Debug.Log("-------------------" + i); } yield return StartCoroutine("H"); //协程1 for (int i = 0; i < 100; i++) //循环C { UnityEngine.Debug.Log(">>>>>>>>>>>>>>>>>>>>" + i); yield return null; //协程1 } } IEnumerator H() { for (int i = 0; i < 5; i++) //循环D { UnityEngine.Debug.Log("NIH" + i); yield return null; } } // 更新数据 void Update() { UnityEngine.Debug.Log("Update"); } //晚于更新 void LateUpdate() { UnityEngine.Debug.Log("------LateUpdate"); }结果:
可以看出:先执行循环B,然后进入yield return StartCoroutine("H"),这时候执行协程方法H,并等待,直到该协程方法执行完再执行后面的内容;
在H中打印了一次NH0就被挂起,需要等待下一帧,这时候执行A循环,然后等到下一帧回到H打印NH1,再挂起等待下一帧,知道H走完,下一帧才会走yield return StartCoroutine("H")后面的代码。
关于Unity协程几种yield的用法,可参考:http://blog.csdn.net/qq_33337811/article/details/73060882。
- unity 协程原理与线程的区别
- unity 协程原理与线程的区别
- Unity协程原理、与线程的区别
- 【Unity】协程原理与线程的区别
- Unity 协程与线程区别
- Unity协程和线程的区别
- 向量的点乘、叉乘在Unity中的应用区别与原理
- 进程、线程、协程的联系与区别
- Unity子线程与主线程通信
- java线程同步原理及wait,notify的用法及与sleep的区别
- java线程同步原理及wait,notify的用法及与sleep的区别
- java线程同步原理及wait,notify的用法及与sleep的区别
- java线程同步原理及wait,notify的用法及与sleep的区别
- java线程同步原理及wait,notify的用法及与sleep的区别
- java线程同步原理及wait,notify的用法及与sleep的区别
- java线程同步原理、wait,notify的用法及与sleep的区别
- java线程同步原理及wait,notify的用法及与sleep的区别
- Daemon线程与普通线程的区别
- Tomcat相关问题
- HTML5-表格标签
- java实现简单聊天程序(集合,线程,I/O,网络编程)
- CMU邢波等最新论文:GAN和VAE的殊途同归,第一作者评述
- 读写INI
- Unity协程原理、与线程的区别
- 从本质理解C指针的应用(1)
- jQuery的概述总结
- 接口,我想和你谈谈
- VB-Instr、Str、Replace、Format
- 我的学习之路_第十三章_网络协议
- Selenium操作示例——鼠标悬停显示二级菜单,再点击二级菜单或下拉列表
- dubbo负载均衡
- 匿名函数和内置函数