协程结束——实测

协程生命周期核心规则

协程是在 MonoBehaviour 实例 上运行的。它的生命周期依赖于该 MonoBehaviour 的 活动状态 以及 GameObject 的状态


物体设置

每个物体均挂载测试脚本


1. 正常结束 ✅ 会结束

  • 协程执行完最后一个 yield,方法自然返回 → 正常结束

  • 这是最常规的情况。


2. 所在 MonoBehaviour 被禁用 ❌ 不会结束

复制代码

一秒记录一次,第二秒暂停脚本,协程仍在运行

结果 :协程仍然会继续运行,不会结束。

⚠️ 重要enabled = false 只禁用 UpdateFixedUpdateLateUpdate 等生命周期方法,对协程没有影响 。协程独立于 enabled 状态运行。

一直在运行->update标识,后续就没有输出了


3. 所在 GameObject 被禁用 ❌ 不会结束?(需要分情况)

立即被禁用

没有继续了

重新开启

结果

GameObject 被禁用后 协程行为
立即被禁用 协程会暂停 ,但不会结束
稍后重新激活 协程从中断的地方继续执行????测试尚未恢复运行

⚠️ 关键点 :GameObject 被禁用后,协程不会运行 ,但协程状态被保留。重新激活后,协程会从上次 yield 的位置继续。


4. 所在 GameObject 被销毁 ✅ 会结束(被强制终止)

结果 :协程立即被终止,不会再执行任何代码。(第二秒终止,所有的都没有输出了)

Destroy(gameObject)Destroy(this) 被调用时,Unity 会清理该 MonoBehaviour 上所有正在运行的协程。


5. 场景切换 ✅ 会结束(除非特殊标记)

结果

场景切换方式 协程行为
SceneManager.LoadScene() 协程被终止
SceneManager.LoadSceneAsync() 协程被终止
加载时标记 DontDestroyOnLoad 的对象 ✅ 协程继续运行(因为对象没有被销毁)

⚠️ 场景切换时,未标记 DontDestroyOnLoad 的所有 GameObject 都会被销毁,因此其上的协程自然被终止。


6. 调用 StopCoroutine / StopAllCoroutines ✅ 会结束

结果 :协程立即被终止,不会继续执行。

注意:StopCoroutine(string methodName) 也可以停止,但推荐使用 Coroutine 对象的方式,避免重名问题。


完整总结表

场景 协程是否会结束 备注
1. 正常执行完毕 ✅ 结束 自然返回
2. MonoBehaviour 禁用 (enabled = false) 不会结束 协程独立于 enabled 运行
3. GameObject 禁用 (SetActive(false)) 但暂停
4. GameObject 销毁 (Destroy) 强制终止 协程被清理
5. 场景切换(未标记 DontDestroyOnLoad) 强制终止 对象被销毁
6. 调用 StopCoroutine / StopAllCoroutines 强制终止 手动停止

常见避坑建议

坑 1:以为禁用脚本就能停止协程

复制代码
enabled = false; // 协程还在跑!

正确做法 :需要停止协程时,显式调用 StopCoroutineStopAllCoroutines

坑 2:尚未切换开启的协程

  • 每次调用 Coroutinee(),都会创建一个全新的、未启动的协程实例
  • StopCoroutine 收到的,只是这个 "新创建的、没跑过的协程",而不是你之前 StartCoroutine 启动的那个
  • 结果就是:你停的是一个不存在的东西,原来的协程还在后台跑,完全不受影响

所以要接收,调用指定协程

代码

cs 复制代码
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class TestCooroutine : MonoBehaviour
{
    public string goName;
    public TestCooroutine testCooroutine;
    public Coroutine thisCoroutine;

    private void Start()
    {
        goName = gameObject.name;
        thisCoroutine = StartCoroutine(Coroutinee());
        testCooroutine = GetComponent<TestCooroutine>();
    }


    private void Update()
    {
        // Debug.Log("一直在运行奥");
        if (Input.GetKeyDown(KeyCode.Q))
        {
            testCooroutine.enabled = false;
        }
        else if (Input.GetKeyDown(KeyCode.W))
        {
            gameObject.SetActive(false); // 禁用整个 GameObject
        }
        else if (Input.GetKeyDown(KeyCode.E))
        {
            Destroy(gameObject); // 销毁 GameObject
        }
        else if (Input.GetKeyDown(KeyCode.R))
        {
            StopCoroutine(Coroutinee());
        }
        else if(Input.GetKeyDown(KeyCode.T))
        {
            SceneManager.LoadScene("Test2");
        }
        else if (Input.GetKeyDown(KeyCode.Y))
        {
            enabled = false;
        }
        else if (Input.GetKeyDown(KeyCode.U))
        {
             StopAllCoroutines();
        }
        else if (Input.GetKeyDown(KeyCode.I))
        {
            StopCoroutine(thisCoroutine);
        }
        
    }

    IEnumerator Coroutinee()
    {
        int circle = 15;
        while (circle > 0)
        {
            Debug.Log(goName + ":" + circle--);
            yield return new WaitForSeconds(1);
        }
        Debug.Log(goName+"已结束正常并退出");
    }
}
cs 复制代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class Test2 : MonoBehaviour
{
    private List<GameObject> _go;
    private void Start()
    {
        var test = FindObjectsOfType<TestCooroutine>().ToList();
        _go = test.Select(x => x.gameObject).ToList();
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.O))
        {
            for (int i = 0; i < _go.Count; i++)
            {
                _go[i].SetActive(true);
            }
            Debug.Log("恢复了");
        }
    }
}
相关推荐
余额瞒着我当琳2 小时前
C++--深拷贝三件套 + swap + 写时拷贝 + vector 扩容 + reserve
java·开发语言·c++
坐吃山猪2 小时前
WebClient内存配置解析
开发语言·springboot·webflux
jdksjw3 小时前
同步与异步、阻塞与非阻塞、多线程、协程超详细讲解(Python并发编程从入门到精通)
开发语言·python
Zach_菠萝侠3 小时前
【DeepSeek Harness 研究】进化方向4:安全加固 思考、设计与实现
开发语言·安全·deepseek
SL-staff3 小时前
技术实践:HR如何用JVS-Logic可视化编排实现考勤数据同步(含节点配置与异常处理)
开发语言·python·低代码·钉钉·可视化编排·jvs-logic·hr技术
曹牧4 小时前
C#:数字的定义和表示方式
算法·c#
SomeB1oody4 小时前
【RustyML入门】6.0. 数学工具
开发语言·后端·机器学习·rust·教程
进制树5 小时前
【飞控开发实战·⑲】ROS2无人机开发环境搭建:Jazzy安装、工作空间与hello_drone节点实战
开发语言·安全·无人机·课程设计
牛马也想出海5 小时前
亚马逊爬虫代理IP:IP类型选择与配置指南
开发语言·php
菜冻鱼5 小时前
Python-pytorch-高级技巧
开发语言·人工智能·pytorch·python·深度学习·神经网络·聚类