1 简介

1)协程概念

​ 协同程序(Coroutine)简称协程,是伴随主线程一起运行的程序片段,是一个能够暂停执行的函数,用于解决程序并行问题。协程是 C# 中的概念,由于 Unity3D 的渲染操作是基于帧实现的,使用线程(Thread)不便于控制,因此 Unity3D 选择使用协程实现并发效果。

​ 协程并不是取代线程,而且抽象于线程之上。线程是系统调度的基本单位,是被分割的 CPU 资源;协程是组织好的代码流程,同一时间其实只有一个协程拥有运行权,相当于单线程的能力。协程需要线程来承载运行,线程是协程的资源,但协程不会直接使用线程,协程直接利用的是执行器(Interceptor),执行器可以关联任意线程或线程池,可以是当前线程、UI线程、新建线程.。

​ 协程是一个能够暂停执行的函数,在收到中断指令后暂停执行,并立即返回主函数,执行主函数剩余的部分,直到中断指令完成后,从中断指令的下一行继续执行协程剩余的部分。函数体全部执行完成,协程结束。协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。由于中断指令的出现,使得可以将一个函数分割到多个帧里执行。

2)中断指令

// 协程在所有脚本的FixedUpdate执行之后,等待一个fixed时间间隔之后再继续执行
yield return WaitForFixedUpdate();
// 协程将在下一帧所有脚本的Update执行之后,再继续执行
yield return null;
// 协程在延迟指定时间,且当前帧所有脚本的 Update全都执行结束后才继续执行
yield return new WaitForSeconds(seconds);
// 与WaitForSeconds类似, 但不受时间缩放影响
yield return WaitForSecondsRealtime(seconds);
// 协程在WWW下载资源完成后,再继续执行
yield return new WWW(url);
// 协程在指定协程执行结束后,再继续执行
yield return StartCoroutine();
// 当返回条件为假时才执行后续步骤
yield return WaitWhile();
// 等待帧画面渲染结束
yield return new WaitForEndOfFrame();

​ 补充:中断对象可以使用静态全局变量,避免产生过多临时对象、频繁触发 GC。

3)协程的执行周期

4)协程与线程的区别

  • 一个线程可以有多个协程;
  • 线程是协程的资源,协程通过 Interceptor 来间接使用线程这个资源;
  • 线程是同步机制,必须等待方法执行完才能返回执行后续方法;协程是异步机制,不需要等方法执行完就可以返回继续执行后续方法;
  • 线程是抢占式,进行线程切换,需要使用锁机制,多线程执行顺序具有一定随机性;协程是非抢占式的,多协程执行顺序由其启动顺序决定。

2 协程的使用

1)创建协程

private IEnumerator CorutineTest() {
Debug.Log("CorutineTest, 1");
yield return null;
Debug.Log("CorutineTest, 2");
yield return new WaitForSeconds(0.05f);
Debug.Log("CorutineTest, 3");
yield return new WaitForFixedUpdate();
Debug.Log("CorutineTest, 4");
yield return new WWW("https://mazwai.com/download_new.php?hash=b524357ef93c1e6ad0245c04c721e479");
Debug.Log("CorutineTest, 5");
}

2)启动协程

private void Start() {
// 形式一
StartCoroutine(CorutineTest());
StartCoroutine(CorutineTest("arg"));
// 形式二, 此方式最多只能传1个参数
StartCoroutine("CorutineTest");
StartCoroutine("CorutineTest", "arg");
// 形式三
IEnumerator corutin = CorutineTest();
StartCoroutine(corutin);
}

3)停止协程

public void StopCoroutine(Coroutine routine);
public void StopCoroutine(IEnumerator routine);
public void StopCoroutine(string methodName); // 只能停止用字符串方法启动的协程
public void StopAllCoroutines();
yield break; // 跳出协程

4)Start 协程

private IEnumerator Start() { // 此时程序中不能再有其他Start方法
yield return StartCoroutine(CorutineTest());
}

3 协程的应用

1)案例一

using System.Collections;
using UnityEngine; public class CorutineController : MonoBehaviour {
private void Start() {
Debug.Log("Start-before");
StartCoroutine(CorutineTest(3));
Debug.Log("Start-after");
} private void Update() {
Debug.Log("Update");
} private IEnumerator CorutineTest(int count) {
Debug.Log("CorutineTest, start");
yield return null;
for (int i = 0; i < count; i++) {
Debug.Log("CorutineTest, " + i);
yield return null;
}
Debug.Log("CorutineTest, end");
}
}

​ 运行结果如下:

​ 从运行结果中可以看出:协程中的方法 CorutineTest 并没有阻塞 Satrt 的后续代码及 Update 方法执行。

2)案例二

​ 在 Hierarchy 窗口创建 Image 对象,并给其添加 CorutineController 脚本组件,如下:

​ CorutineController.cs

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using System.IO; public class CorutineController : MonoBehaviour {
private Image image; private void Awake() {
image = GetComponent<Image>();
StartCoroutine(DownLoadPicture());
} private IEnumerator DownLoadPicture() {
WWW www = new WWW("https://i0.hdslb.com/bfs/article/f04bc0a016e6d88c602047a39364a42cb27ea170.jpg@942w_531h_progressive.jpeg");
// yield return www; // 等待www下载完毕
while (!www.isDone) {
Debug.Log("CorutineTest, progress = " + www.progress); // 打印下载进度
yield return null; // 等待www下载完毕
}
Texture2D texture = www.texture;
texture.name = "girl";
image.sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
GetComponent<RectTransform>().sizeDelta = new Vector2(texture.width, texture.height);
File.WriteAllBytes(Application.dataPath + "/CorutineScene/girl.jpeg", www.bytes); // 保存图片
}
}

​ 运行效果:

​ 声明:本文转自【Unity3D】协同程序

【Unity3D】协同程序的更多相关文章

  1. Unity3D协同程序(Coroutine)

    摘要下: 1. coroutine, 中文翻译"协程".这个概念可能有点冷门,不过百度之,说是一种很古老的编程模型了,以前的操作系统里进程调度里用到过,现在操作系统的进程调度都是根 ...

  2. (转)Unity3D协同程序(Coroutine)

    一.什么是协同程序 协同程序,即在主程序运行时同时开启另一段逻辑处理,来协同当前程序的执行.换句话说,开启协同程序就是开启一个线程. 二.协同程序的开启与终止 在Unity3D中,使用MonoBeha ...

  3. Coroutine协同程序介绍(Unity3D开发之三)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=496 Coroutine在Uni ...

  4. 【转】关于Unity协同程序(Coroutine)的全面解析

    http://www.unity.5helpyou.com/2658.html 本篇文章我们学习下unity3d中协程Coroutine的的原理及使用 1.什么是协调程序 unity协程是一个能暂停执 ...

  5. Lua 学习笔记(九)协同程序(线程thread)

    协同程序与线程thread差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和命令指针,同时又与其他协同程序共享全局变量和其他大部分东西.从概念上讲线程与协同程序的主要区别在于,一个具有多个线程的 ...

  6. 使用Monitor调试Unity3D Android程序日志输出(非DDMS和ADB)

    使用Monitor调试Unity3D Android程序日志输出(非DDMS和ADB) http://www.cnblogs.com/mrkelly/p/4015245.html 以往调试Androi ...

  7. 【转】Unity中的协同程序-使用Promise进行封装(三)

    原文:http://gad.qq.com/program/translateview/7170967 译者:崔国军(飞扬971)    审校:王磊(未来的未来) 在这个系列的最后一部分文章,我们要通过 ...

  8. 【转】Unity中的协同程序-使用Promise进行封装(二)

    原文:http://gad.qq.com/program/translateview/7170970 译者:王磊(未来的未来)    审校:崔国军(飞扬971)   在上一篇文章中,我们的注意力主要是 ...

  9. 【转】Unity中的协同程序-使用Promise进行封装(一)

    原文:http://gad.qq.com/program/translateview/7170767 译者:陈敬凤(nunu)    审校:王磊(未来的未来) 每个Unity的开发者应该都对协同程序非 ...

  10. Lua中的协同程序 coroutine

    Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换.不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时 ...

随机推荐

  1. Clock Domain Crossing

    Clock Domain Crossing CDC问题主要有亚稳态问题,多比特信号同步,握手信号同步,异步Fifo等 Topics Describe the SoC Design Issues Und ...

  2. -- spi flash 擦除接口调用HAL库不同函数的区别

    [描述] 在使用STM32F429操作W25Q128时,为验证flash工作正常,做简单的读写数据校验,在擦除接口中使用 HAL_SPI_Transmit 方法一直工作异常,使用 HAL_SPI_Tr ...

  3. Go-数据类型-数字

    Go数字类型 整数 int 类 int(在32机器上为int32,在64位机器上为int64) int8 int16 int32 int64 unit类 uint(在32机器上为uint32,在64位 ...

  4. [转帖]SCSI、ISCSI、iSER、NVMe、NVMe-oF、NVMe-oF over RDMA

    在存储系统中,上层协议可以泛指"指令",也就是比如"读出从某某开始的多少长度的扇区",指令包含三大关键信息: (1)操作码:Opreation Code,或称为 ...

  5. [转帖]LVS入门篇(五)之LVS+Keepalived实战

    LVS入门篇(五)之LVS+Keepalived实战 https://www.cnblogs.com/linuxk/p/9365189.html 一.实验架构和环境说明 (1)本次基于VMware W ...

  6. [转帖]超线程SMT究竟可以快多少?(AMD Ryzen版 )

    https://www.modb.pro/db/139224 昨天我们用Intel I9的10核,每个核2个threads的机器跑了内核的编译: 超线程SMT究竟可以快多少? 今天,我换一台机器,采用 ...

  7. [转帖]linux下 进程io队列,IO队列和IO调度

    IO体系概览 先看看本文主题IO调度和IO队列处于整个IO体系的哪个位置,这个IO体系是非常重要的,了解IO体系我们可以对整个IO过程有个全面的认识.虽然一下两下并不清楚IO体系各个部分的细节,但是我 ...

  8. 最简单的以CentOS为base images 安装 Nodejs等操作的方法

    镜像内安装NodeJS的简单方法 公司内有产品需要安装nodejs以便进行相关操作,Linux和Windows时没有问题,但是如果是镜像的话可能会稍微复杂一点, 这里简单进行一下总结, 以便备忘. 1 ...

  9. XCODE IOS 静态链接库替换升级

    XCODE 版本15.2. 一个很久需求没更新的IOS 应用,近来有新需求要开发. 拉下代码运行,出现了个BAD_ACCESS错误.出错的位置位于一个调用的第三方的.a静态库内部.因为调用代码并没有修 ...

  10. 微信对话平台API开发

    接入官方文档接入文档 下面我们开始使用前端来进行接入 <!DOCTYPE html> <html> <head> <meta charset="UT ...