unity 协程

article/2025/11/1 6:12:56

首先声明:协程不是线程,协程在主线程中运行,而线程是单独开辟线程

以下是u3d关于协程的调用机制的解释:

“在Unity3D中,使用MonoBehaviour.StartCoroutine方法即可开启一个协同程序,也就是说该方法必须在MonoBehaviour或继承于MonoBehaviour的类中调用。

       在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启一个线程。区别在于使用字符串作为参数可以开启线程并在线程结束前终止线程,相反使用IEnumerator 作为参数只能等待线程的结束而不能随时终止(除非使用StopAllCoroutines()方法);另外使用字符串作为参数时,开启线程时最多只能传递一个参数,并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制。

        在Unity3D中,使用StopCoroutine(string methodName)来终止一个协同程序,使用StopAllCoroutines()来终止所有可以终止的协同程序,但这两个方法都只能终止该MonoBehaviour中的协同程序。

        还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;如是将协同程序所在脚本的enabled设置为false则不会生效。这是因为协同程序被开启后作为一个线程在运行,而MonoBehaviour也是一个线程,他们成为互不干扰的模块,除非代码中用调用,他们共同作用于同一个对象,只有当对象不可见才能同时终止这两个线程。然而,为了管理我们额外开启的线程,Unity3D将协同程序的调用放在了MonoBehaviour中,这样我们在编程时就可以方便的调用指定脚本中的协同程序,而不是无法去管理,特别是对于只根据方法名来判断线程的方式在多人开发中很容易出错,这样的设计保证了对象、脚本的条理化管理,并防止了重名。”
 

问题1:同一个协程可以多次开启吗?

答:可以,但是每重复开启一次,代表重新开启了一个新的协程。以下脚本运行时,Start开启了协程“A”两次,根据输出结果发现相当于开启了两个独立协程,

可以用StopCoroutine("A")同时停止开启的两个协程“A”;

{当StartCoroutine("A", "a")等待时被挂起,开始执行协程StartCoroutine("A", "b"); 或是:StartCoroutine("A", "a")、StartCoroutine("A", "b")两个协程同时执行,不存在先后顺序? 这里一直没弄懂,有懂的麻烦告知一下}

public class Test : MonoBehaviour
{void Start(){StartCoroutine("A", "a");StartCoroutine("A", "b");}void Update(){if (Input.GetKeyDown(KeyCode.A)){StopCoroutine("A");}}IEnumerator A(string a){while (true){Debug.LogError(a);yield return new WaitForSeconds(3f);}}
}

问题2:协程开启后可以自己关闭自己吗?

答:可以,在协程内部调用关闭方法关闭自己,StopCoroutine("Method");

当在协程内部停止自身后,后面的代码块还会继续执行,直到遇到yield语句才会终止。

经测试:停止协程,意味着就是停止yield,所以在停止协程后,yield之后的语句也就不会执行了,但yield之前的方法还可继续执行,测试如下

public class Test : MonoBehaviour
{int num;void Start(){StartCoroutine("A", "a");}void Dotest(){Debug.Log("Dotest:" + num);}IEnumerator A(string a){StopCoroutine("A");for (int i = 0; i < 1000; i++){num += i;}        Dotest();yield return new WaitForSeconds(3f);Debug.Log(num);}
}

未解决: 

未解决问题1:多个协程开启是都执行吗?还是当一个挂起后再执行下一个?(例如开启两个协程下载电影,这俩电影同时下载吗?)(下方引用有解决)

未解决问题2:协程开启后会自动结束吗?是yield后自动关闭吗? 需要自己去手动关闭吗?没关闭有影响吗?

 

//以下内容转载自 :https://zhuanlan.zhihu.com/p/59619632,作者:汪文魁

什么是协同程序?什么是协程?
unity协程是一个能够暂停协程执行,暂停后立即返回主函数,执行主函数剩余的部分,直到中断指令完成后,从中断指令的下一行继续执行协程剩余的函数。函数体全部执行完成,协程结束。
由于中断指令的出现,使得可以将一个函数分割到多个帧里去执行。
性能:
在性能上相比于一般函数没有更多的开销
协程的好处:
让原来要使用异步 + 回调方式写的非人类代码, 可以用看似同步的方式写出来。
能够分步做一个比较耗时的事情,如果需要大量的计算,将计算放到一个随时间进行的协程来处理,能分散计算压力
协程的坏处:
协程本质是迭代器,且是基于unity生命周期的,大量开启协程会引起gc
如果同时激活的协程较多,就可能会出现多个高开销的协程挤在同一帧执行导致的卡帧
协程书写时的性能优化:
常见的问题是直接new 一个中断指令,带来不必要的 GC 负担,可以复用一个全局的中断指令对象,优化掉开销;在 Yielders.cs 这个文件里,已经集中地创建了上面这些类型的静态对象
这个链接分析了一下https://blog.csdn.net/liujunjie612/article/details/70623943
协程是在什么地方执行?
协程不是线程,不是异步执行;协程和monobehaviour的update函数一样也是在主线程中执行
unity在每一帧都会处理对象上的协程,也就是说,协程跟update一样都是unity每帧会去处理的函数
经过测试,协程至少是每帧的lateUpdate后运行的。
参照unity的生命周期图


协程怎么结束?
方法一:StopCoroutine(string methodName);
方法二:stopAllCoroutines暂停的是当前脚本下的所有协程
方法三:gameObject.active = false 可以停止该对象上全部协程的执行,即使再次激活,也不能继续执行。但注意MonoBehaviour enabled = false 不能停止协程;对比 update却是可以在MonoBehaviour enabled = false 就中止
原因:由于协程在StartCoroutine时被注册到的GameObject上,他的生命期受限于GameObject的生命期,因此受GameObject是否active的影响。
结论:协程虽然是在MonoBehvaviour启动的(StartCoroutine)但是协程函数的地位完全是跟MonoBehaviour是一个层次的,不受MonoBehaviour的状态影响。
协程结束的标志是什么?
如果最后一个 yield return 的 IEnumerator 已经迭代到最后一个是,MoveNext 就会 返回 false 。这时,Unity就会将这个 IEnumerator 从 cortoutines list 中移除。
只有当这个对象的 MoveNext() 返回 false 时,即该 IEnumertator 的 Current 已经迭代到最后一个元素了,才会执行 yield return 后面的语句。
中断函数类型:
null 在下一帧所有的Update()函数调用过之后执行

WaitForSeconds() 等待指定秒数,在该帧(延迟过后的那一帧)所有update()函数调用完后执行。即等待给定时间周期, 受Time.timeScale影响,当Time.timeScale = 0f 时,yield return new WaitForSecond(x) 将不会满足。

WaitForFixedUpdate 等待一个固定帧,即等待物理周期循环结束后执行

WaitForEndOfFrame 等待帧结束,即等待渲染周期循环结束后执行

StartCoroutine 等待一个新协程暂停

WWW 等待一个加载完成,等待www的网络请求完成后,isDone=true后执行


协程的执行顺序:
开始协程->执行协程->遇到中断指令中断协程->返回上层函数继续执行上层函数的下一行代码->中断指令结束后,继续执行中断指令之后的代码->协程结束
协程可以嵌套协程吗?
可以,yield return StartCoroutine就是,执行顺序是:
子协程中断后,会返回父协程,父协程暂停,返回父协程的上级函数。
决定父协程结束的标志是子协程是否结束,当子协程结束后返回父协程执行其后的代码才算结束。
同一时刻同一脚本实例中能有多少个运行的协程?
在一个MonoBehaviour提供的主线程里只能有一个处于运行状态的协程。因为协程不是线程,不是并行的。同一时刻、一个脚本实例中可以有多个暂停的协程,但只有一个运行着的协程
协程和线程的区别?
线程是利用多核达到真正的并行计算,缺点是会有大量的锁、切换、等待的问题,而协程是非抢占式,需要用户自己释放使用权来切换到其他协程, 因此同一时间其实只有一个协程拥有运行权, 相当于单线程的能力。
协程是 C# 线程的替代品, 是 Unity 不使用线程的解决方案。
使用协程不用考虑同步和锁的问题
多个协程可以同时运行,它们会根据各自的启动顺序来更新
其他注意点:
1、IEnumerator 类型的方法不能带 ref 或者 out 型的参数,但可以带被传递的引用
2、在函数 Update 和 FixedUpdate 中不能使用 yield 语句,否则会报错, 但是可以启动协程
3、在一个协程中,StartCoroutine()和 yield return StartCoroutine()是不一样的。
前者仅仅是开始一个新的Coroutine,这个新的Coroutine和现有Coroutine并行执行。
后者是返回一个新的Coroutine,是一个中断指令,当这个新的Coroutine执行完毕后,才继承执行现有Coroutine。

 

 

 

 

 

 


http://chatgpt.dhexx.cn/article/rBWkNZQ9.shtml

相关文章

【Unity】Unity协程(Coroutine)的原理与应用

文章目录 前言一、什么是协程二、应用场景1.异步加载资源2.将一个复杂程序分帧执行3.定时器 三、协程的使用注意事项 四、Unity协程的底层原理1. 协程本体&#xff1a;C#的迭代器函数2. 协程调度&#xff1a;MonoBehaviour生命周期中实现 五、参考资料 前言 本文是作者在学习U…

Unity-协程详解

1. 简介 unity的**协程&#xff08;Coroutine&#xff09;**只是在c#的基础上做了一层封装&#xff0c;其实yield是C#的关键字。 unity协程是一个能够暂停协程执行&#xff0c;暂停后立即返回主函数&#xff0c;执行主函数剩余的部分&#xff0c;直到中断指令完成后&#xff…

Unity 协程(Coroutine)原理与用法详解

前言&#xff1a; 协程在Unity中是一个很重要的概念&#xff0c;我们知道&#xff0c;在使用Unity进行游戏开发时&#xff0c;一般&#xff08;注意是一般&#xff09;不考虑多线程&#xff0c;那么如何处理一些在主任务之外的需求呢&#xff0c;Unity给我们提供了协程这种方式…

linux的用户管理

1.linux的用户管理 linux的用户管理和组管理&#xff0c; 每个用户都必须要有一个且仅有一个初始组&#xff0c;可以有多个附加组&#xff0c;使用useradd命令创建用户时&#xff0c;如果没有指定初始组&#xff0c;系统默认会创建一个于其同名的组。 用户和组信息保存在4个文…

Linux用户管理练习

Linux下用户分为3类&#xff1a;超级用户&#xff08;root&#xff09;、系统用户、普通用户。 超级用户的用户名为root&#xff0c;它具有一切操作权力&#xff0c;因此为安全起见&#xff0c;建议不要轻易的在root账户下面对文件进行操作。在Linux操作系统的字符界面&#xf…

Linux用户管理工具

Linux用户管理工具 1. 用户 1.1创建用户 useradd -m username该命令为用户创建相应的帐号和用户目录/home/username&#xff1b; passwd username该命令为用户设置密码 1.2 删除用户 userdel -r username不带选项使用 userdel&#xff0c;只会删除用户。用户的家目录将…

Linux上的用户管理

Linux是一个多用户多任务的系统&#xff0c;任何人想要访问系统资源&#xff0c;必须通过登录账号来访问系统资源 添加用户 useradd&#xff1a;添加用户的命令&#xff08;root才能添加用户&#xff09; 用法&#xff1a;useradd 用户名 例&#xff1a;useradd water 就创建…

实现Linux用户管理

1.添加用户组&#xff1a;groupadd 用户组名称 2.创建用户 &#xff08;一&#xff09;仅创建用户&#xff1a;useradd 用户名 &#xff08;二&#xff09;指定用户所属的用户组&#xff1a; useradd -g 用户组 3.设置用户密码 &#xff08;一&#xff09;passwd 普通用户名 …

linux用户管理及操作指令

1、首先了解下linux是一个多用户多任务的操作系统。任何一个需要使用资源的用户都需要从linux系统中分配一个用户角色&#xff0c;比如&#xff1a;root、user、、然后使用对应账号进入系统。一个root用户下面能创建多个用户&#xff0c;每个用户下面对应一个目录 2、添加用户…

浅谈Linux用户管理

Linux用户管理 准备工作&#xff1a; 在管理用户时&#xff0c;执行命令后是无法看到效果的&#xff0c;最开始我们可以通过系统监视命令来对用户信息进行监控&#xff0c;使操作步骤可视。 watch -n 1 tail -n3 /etc/passwd;ls -l /home/ 注释&#xff1a; 部分含义watch …

Linux用户管理(Centos7)

用户管理 用户命令 添加登录用户&#xff1a; 例&#xff1a;添加一个名为harry的用户&#xff0c;并使用bash作为登录的shell [rootaws ~]# useradd harry [rootaws ~]# tail -1 /etc/passwd harry:x:1002:1002::/home/harry:/bin/bashharry:x:1001:1001::/home/harry:/bin/…

Linux用户管理机制

Linux系统中的用户管理涉及用户账号文件 /etc/passwd、用户密码文件 /etc/shadow、用户组文件 /etc/group。 一、用户账号文件 /etc/passwd 该文件为纯文本文件&#xff0c;可以使用cat、head等命令查看。该文件记录了每个用户的必要信息&#xff0c;文件中的每一行对应一个用…

【Linux用户管理】

目录 前言 用户管理的基本命令 前言 Linux是一个多用户、多任务的操作系统&#xff0c;具有很好的稳定性与安全性&#xff0c;在linux系统中&#xff0c;root用户具有最高的权限&#xff0c;但该身份不当使用会带来一些不必要的麻烦和潜在的风险&#xff0c;故需要添加一些普通…

Linux之用户管理

一、用户的增删改查 1.增加用户 语法&#xff1a;useradd用户名 在终端输入 useradd 用户名 在linux系统home文件夹下面会出现新建用户的文件夹 2.修改密码 语法&#xff1a;passwd用户名 输入passwd 用户名&#xff0c;输入新的密码之后就可以使用新建的用户登录 3.删除用…

Linux用户管理-相关命令及配置文件-超详细-概念详解-初学全

前言 Linux系统作为多用户多任务的操作系统&#xff0c;可以在同一时间内允许多个用户登录、操作及配置计算机&#xff0c;随着需求的增加&#xff0c;用户的增加&#xff0c;我们也就需要对用户进行管理&#xff0c;以至于更有效地开展项目&#xff0c;改善工作&#xff0c;更…

Ubuntu/Linux用户管理与权限管理(超详细解析)

由于实验室几个老师的学生要共同使用一台服务器&#xff0c;所以需要规范一下服务器的使用&#xff0c;并且给各位学生配置相关的用户和权限&#xff0c;之前一直都是自己用&#xff0c;所以借此机会学习和总结一下Linux服务器的用户管理与权限管理。 Ubuntu/Linux用户管理与权…

轻松搞懂Linux中的用户管理

文章目录 概念用户账户用户组用户权限用户管理工具 概念 用户管理是Linux系统管理员必须掌握的重要技能之一。Linux系统是一个多用户操作系统&#xff0c;可以支持多个用户同时使用&#xff0c;每个用户拥有自己的账户和权限&#xff0c;因此管理员需要了解如何创建、管理和删…

Linux用户管理相关命令(全)

1、Linux用户(账号)管理 查询用户(账号)信息&#xff08;判断用户(账号)是否存在&#xff09; id account新增用户(账号) useradd account设置用户(账号)密码 方式1&#xff1a; passwd account 方式2&#xff1a; echo 123|passwd --stdin account; #密码为123删除用户(账…

Linux用户管理、组管理及权限管理

文章目录 Linux用户管理whoami指令who指令useradd指令userdel指令passwd指令usermod指令 - 修改已有账号自身的信息id指令 - 查询用户信息 Linux用户组管理groupadd 指令groupdel指令groupmod - 修改用户组自身的属性groups指令 - 显示用户所属组 Linux权限的概念su指令sudo指令…