Unity是否支持多线程?
- Unity是支持多线程的, 只是新开线程无法访问Unity相关对象的内容
- 注意:Unity中的多线程要记住关闭,否则即使停止运行主线程新开线程也会继续运行
协同程序是什么?
- 协同程序简称协程,它是“假”的多线程,它不是多线它的主要作用
- 将代码分时执行,不卡主线程
- 主要使用场景
- 异步加载文件
- 异步下载文件
- 场景异步加载
- 批量创建时防止卡顿
协同程序和线程的区别
- 新开一个线程是独立的一个管道,和主线程并行执行
- 新开一个协程是在原线程之上开启,进行逻辑分时分步执行
协程的使用
- 继承MonoBehavior的类 都可以开启 协程函数
第一步:申明协程函数
- 协程函数2个关键点
- 1-1返回值为IEnumerator类型及其子类
- 1-2函数中通过 yield return 返回值;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| IEnumerator MyCoroutine(int i, string str) { print(i); yield return null; print(str); yield return new WaitForSeconds(1f); print("2"); yield return new WaitForFixedUpdate(); print("3"); yield return new WaitForEndOfFrame(); while(true) { print("5"); yield return new WaitForSeconds(5f); } }
|
第二步:开启协程函数
1 2
| IEnumerator ie = MyCoroutine(1, "123"); StartCoroutine(ie);
|
第三步:关闭协程
1 2
| Coroutine c1 = StartCoroutine(MyCoroutine(1,"123")); StopCoroutine(c1);
|
yield return 不同内容的含义
下一帧执行
1 2
| yield return 数字; yield return null;
|
等待指定秒后执行
1
| yield return new WaitForSeconds(second);
|
等待下一个固定物理帧更新时执行
1
| yield return new WaitForFixedUpdate();
|
- 在FixedUpdate和碰撞检测相关函数之后执行
等待摄像机和GUI渲染完成后执行
1
| yield return new WaitForEndOfFrame();
|
- 在LateUpdate之后的渲染相关处理完毕后之执行
一些特殊类型的对象 比如异步加载相关函对象
- 之后讲解:异步加载资源、异步加载场景、网络加载时讲解
- 一般在Update和LateUpdate之间执
跳出协程
协程受对象和组件失活销毁的影响
- 协程开启后
- 组件和物体销毁,协程不执行
- 物体失活协程不执行,组件失活协程执行
- 与延迟函数相比 延迟函数:
- 组件和物体销毁,延迟函数不执行
- 物体失活延迟函数执行,组件失活延迟函数执行
协程的本质
- 协程可以分成两部分
- 协程函数本体
协程本体就是一个能够中间暂停返回的函数,本质上就是一个 C#的迭代器方法 - 协程调度器
协程调度器是Unity内部实现的,会在对应的时机帮助我们继续执行协程函数
- Unity只实现了协程调度部分
理解
C#看到迭代器函数和yield return 语法糖就会把原本是一个的 函数变成"几部分"
我们可以通过迭代器 从上到下遍历这 "几部分"进行执行 就达到了将一个函数中的逻辑分时执行的目的
而协程调度器就是 利用迭代器函数返回的内容来进行之后的处理
比如Unity中的协程调度器 根据yield return 返回的内容 决定了下一次在何时继续执行迭代器函数中的"下一部分"
理论上来说 我们可以利用迭代器函数的特点 自己实现协程调度器来取代Unity自带的调度器
例子:使用协程避免批量加载物体时卡顿
问题:请在场景中创建100000各随机位置的立方体,让其不会明显卡顿
分析:如果在同一帧中同时创建100000个物体,会超出1帧的时间,让玩家感到明显卡顿;
此时可以使用协程分不同帧分批次创建,例如每帧创建1000个,可减少卡顿。
1 2 3 4 5 6 7 8 9 10
| IEnumerator CreateCube(int num) { for(int i=0; i<num; i++) { GameObject obj = GameObject.CreatePrimitive(Primitive.Cube); obj.transform.position = new Vector3(Random.Range(-100, 100),Random.Range(-100, 100),Random.Range(-100, 100)); if(i % 1000 == 0) yield return null; } }
|
总结
- Unity支持多线程,只是新开线程无法访问主线程中Unity相关内容
- 一般主要用于进行复杂逻辑运算或者网络消息接收等等
- 注意:Unity中的多线程一定记住关闭
- 协同程序不是多线程,它是将线程中逻辑进行分时执行,避免卡顿
- 继承MonoBehavior的类都可以使用协程
- 开启协程方法、关闭协程方法
- yield return 返回的内容对于我们的意义
- 协程只有当组件单独失活时不受影响,其它情况协程会停止