Bootstrap

unity3d————协程

一、协程的基本概念

  • 定义:协程是伴随主线程一起运行的程序片段,是一个能够暂停执行的函数。它不是真正的多线程,而是通过状态机实现伪异步,上下文切换消耗小,适用于非密集计算任务。
  • 作用:协程用于解决程序并行问题,常用于延迟执行、分帧处理和非阻塞I/O操作,以避免主线程阻塞。
  • 实现方式:协程基于C#的IEnumerator接口和yield关键字实现,可以视为一种伪异步编程方式。

二、协程的使用

  • 创建协程:创建一个返回IEnumerator类型的函数,这个函数通常被称为协程方法。在协程方法内部,使用yield return语句来暂停协程的执行。
  • 启动协程:使用StartCoroutine函数来启动协程。StartCoroutine可以接受IEnumerator类型的参数,也可以接受字符串形式的方法名(但这种方式最多只能传递一个参数)。
  • 停止协程:使用StopCoroutine或StopAllCoroutines函数来停止协程。停止协程时,需要确保使用与启动协程相同的形式。

三、协程的常用写法与中断指令

  • Yield Return null:暂停协程,直到下一帧再继续。
  • Yield Return WaitForSeconds:暂停协程,等待指定的时间后再继续执行。
  • Yield Return StartCoroutine:暂停当前协程,直到启动的新协程执行完毕。
  • Yield Break:提前退出协程。

四、协程的应用场景

  • 延迟执行:例如,在游戏开始时延迟显示某些界面元素。
  • 分帧处理:将复杂的任务分解成多个步骤,在多个帧之间执行,以避免帧率下降。
  • 非阻塞I/O操作:例如,异步加载资源或网络请求,避免阻塞主线程。

五、协程与线程的区别

  • 实现方式:协程基于C#的IEnumerator接口实现,线程基于系统底层的多线程模型实现。
  • 上下文切换消耗:协程的上下文切换消耗较小,线程间的上下文切换消耗较大。
  • CPU利用:协程运行在Unity3D的主线程上,不能充分利用多核CPU的优势;线程可以运行在操作系统提供的不同的独立执行单元中,实现真正的多任务并行执行。

六、协程的优缺点

  • 优点

    • 协程可以让程序员用类似于同步编码的样式来实现异步操作,从而使代码更易于阅读和理解。
    • 协程的上下文切换消耗小,适用于非密集计算任务。
  • 缺点

    • 协程的本质是迭代器,基于Unity的生命周期,大量开启协程会引起GC(垃圾回收),可能导致性能问题。
    • 如果同时激活的协程较多,多个高开销的协程挤在同一帧执行,可能导致卡顿。

代码示例:

    void Start()
    {
        StartCoroutine(MyCoroutine(1, "123"));
    }

    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);
        }
    }

 

2. StartCoroutine() 方法

  • StartCoroutine(IEnumerator routine) 是用来启动一个协程的方法。它接受一个IEnumerator类型的参数,这个参数通常是一个协程方法的返回值。在这个例子中,StartCoroutine(MyCoroutine(1, "123"))启动了名为MyCoroutine的协程,并传递了两个参数:一个整数1和一个字符串"123"

3. IEnumerator 接口

  • IEnumerator 是C#中用于支持简单迭代的接口。在Unity中,协程通过实现IEnumerator接口来工作。协程方法需要返回IEnumerator<int>(或IEnumerator)类型,并且在方法体内使用yield return语句来指定何时暂停执行以及何时恢复执行。

4. yield return 语句

  • yield return 是C#中的一个特殊语句,用于在迭代器块中产生一个值或暂停迭代器的执行。在协程中,yield return用来暂停协程的执行,直到满足某个条件(如等待一定的时间、等待帧的结束等)。
    • yield return null;:将协程暂停到下一帧。
    • yield return new WaitForSeconds(1f);:将协程暂停1秒。
    • yield return new WaitForFixedUpdate();:将协程暂停到下一个固定更新帧(FixedUpdate)。
    • yield return new WaitForEndOfFrame();:将协程暂停到当前帧的末尾。

关闭协程:

    void Start()
    {
        StartCoroutine(MyCoroutine(1, "123"));


        Coroutine c1 = StartCoroutine(MyCoroutine(1, "123"));
        Coroutine c2 = StartCoroutine(MyCoroutine(1, "123"));
        Coroutine c3 = StartCoroutine(MyCoroutine(1, "123"));

        //关闭所有协程
       // StopAllCoroutines();

        //关闭指定协程
       StopCoroutine(c1);
    }

    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);
        }
    }


        //关闭所有协程
       // StopAllCoroutines();

        //关闭指定协程
       StopCoroutine(c1);

yield return 不同内容的含义: 

        yield return 数字;
        yield return null;
        在Update和LateUpdate之间执行

        2.等待指定秒后执行
        yield return new WaitForSeconds(秒);
        在Update和LateUpdate之间执行

        3.等待下一个固定物理帧更新时执行
        yield return new WaitForFixedUpdate();
        在FixedUpdate和碰撞检测相关函数之后执行

        4.等待摄像机和GUI渲染完成后执行
        yield return new WaitForEndOfFrame();
        在LateUpdate之后的渲染相关处理完毕后之后

        5.一些特殊类型的对象 比如异步加载相关函数返回的对象
        之后讲解 异步加载资源 异步加载场景 网络加载时再讲解
        一般在Update和LateUpdate之间执行

        6.跳出协程
        yield break;

协程受对象和组件失活销毁的影响:
        协程开启后
        组件和物体销毁,协程不执行
        物体失活协程不执行,组件失活协程执行 

 

;