更有效的协同程序【插件:More Effective Coroutines】

news/2024/11/7 9:01:24/

插件地址:传送门

1、命名空间

using System.Collections.Generic;

using MEC;

2、与传统的协程相比

传统:StartCoroutine(_CheckForWin());

被RunCoroutine取代。必须选择执行循环进程,默认为“Segment.Update”。
 


using System.Collections.Generic;
using UnityEngine;
using MEC;public class Test : MonoBehaviour
{void Start(){StartCoroutine(_CheckForWin());// To run in the Update segment:Timing.RunCoroutine(_CheckForWin());// To run in the FixedUpdate segment:Timing.RunCoroutine(_CheckForWin(), Segment.FixedUpdate);// To run in the LateUpdate segment:Timing.RunCoroutine(_CheckForWin(), Segment.LateUpdate);// To run in the SlowUpdate segment:Timing.RunCoroutine(_CheckForWin(), Segment.SlowUpdate);}IEnumerator<float> _CheckForWin(){yield return Timing.WaitForSeconds(1);Debug.Log("****");}
}

3、协程的退出/停止  CancelWith

相当于StopCoroutine,CancelWith确实会增加所有协程生成的不可避免的GC分配的大小大约20个字节。20字节并不大,但是如果您想避免所有可能的GC分配,那么你就可以相对容易地做CancelWith所做的事情,而不用使用这个函数。只是确保在协程中的每个yield return语句之后都做以下检查:if(gameObject != null && gameObject.activeInHierarchy)

public class Cube01 : MonoBehaviour
{private void Awake(){Timing.RunCoroutine(_moveMyButton().CancelWith(gameObject));}IEnumerator<float> _moveMyButton(){while (true){yield return Timing.WaitForSeconds(1f);Debug.Log("********");}}
}

4、停止和回复协程

MEC协程可以暂停,稍后再恢复。Unity的协程不会这样做,但是概念很简单。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MEC;public class Cube01 : MonoBehaviour
{private CoroutineHandle handleToACoroutine;private void Awake(){handleToACoroutine= Timing.RunCoroutine(_moveMyButton().CancelWith(gameObject));}private void Update(){if (Input.GetKeyDown(KeyCode.P)){Timing.PauseCoroutines(handleToACoroutine);}if (Input.GetKeyDown(KeyCode.R)){Timing.ResumeCoroutines(handleToACoroutine);}}IEnumerator<float> _moveMyButton(){while (true){yield return Timing.WaitForSeconds(1f);Debug.Log("********");}}
}

5、等待直到完成

Unity的默认协同程序有几种情况,你可以产生返回一些变量。例如,你可以“yield return asyncOperation;”。MEC也有这样的功能函数称为WaitUntilDone。

        yield return Timing.WaitUntilDone(wwwObject);yield return Timing.WaitUntilDone(asyncOperation);yield return Timing.WaitUntilDone(customYieldInstruction);// With MEC Pro you can do a little more with WaitUntilDone:yield return Timing.WaitUntilDone(newCoroutine);// 上面的代码自动启动一个新的协程,并保存当前的协程。yield returnTiming.WaitUntilTrue(functionDelegateThatReturnsBool);  //免费版没有yield returnTiming.WaitUntilFalse(functionDelegateThatReturnsBool); //免费版没有

6、慢更新(slow update)

Unity的协程没有慢更新循环的概念,但MEC的协程有。
慢更新循环(默认情况下)每秒运行7次。它使用绝对时间刻度,所以当你减慢Unity的时间刻度时,它不会减慢SlowUpdate。使用SlowUpdate和总是使用“yield returnTiming.WaitForSeconds(1f/7f);”有两个主要区别。第一个是绝对时间尺度,第二个是所有的SlowUpdate节拍同时发生。

    private void Awake(){Timing.RunCoroutine(_UpdateTime(), Segment.SlowUpdate);}private float clock;private IEnumerator<float> _UpdateTime(){while (true){//当前段已运行的时间(以秒为单位)。clock = Timing.LocalTime;yield return 0f;}}

SlowUpdate还可以很好地检查临时调试变量。例如,如果重建项目需要很长时间,您可以在脚本中设置一个公共bool值,以重置该脚本上的值。您需要定期检查该bool值是否已设置为true,执行该检查的最佳时间是在SlowUpdate上。当用户选中复选框时,它会感觉它立即响应,但它将在你的应用程序中使用更少的处理每1/7秒检查一次,而不是每秒30 - 100次(取决于你的帧率)。

注意:Unity的Time. deltatime变量在SlowUpdate中不会返回正确的值,因为Unity的Time类对这个片段一无所知。可以使用Timing.DeltaTime代替。

您还可以更改SlowUpdate运行的速率。例如:

Timing.Instance.TimeBetweenSlowUpdateCalls = 3f;

上面这行代码将使SlowUpdate每3秒只运行一次。

7、标签【Tag】

在启动协程时,可以选择是否提供标记。标记是标识该协程的字符串。当您标记一个协程或一组协程时,您可以稍后使用KillCoroutine(标签)或KillAllCoroutines(标签)杀死该协程或该组。【API可能会变,可以查看相关API调用】


using System.Collections.Generic;
using UnityEngine;
using MEC;public class Test : MonoBehaviour
{void Start(){Timing.RunCoroutine(_shout(1, "Hello"), "shout");Timing.RunCoroutine(_shout(2, "World!"), "shout");Timing.RunCoroutine(_shout(3, "I"), "shout2");Timing.RunCoroutine(_shout(4, "Like"), "shout2");Timing.RunCoroutine(_shout(5, "Cake!"), "shout2");Timing.RunCoroutine(_shout(6, "Bake"), "shout3");Timing.RunCoroutine(_shout(7, "Me"), "shout3");Timing.RunCoroutine(_shout(8, "Cake!"), "shout3");Debug.Log("Killed " + Timing.KillCoroutines("shout2"));}IEnumerator<float> _shout(float time, string text){yield return Timing.WaitForSeconds(time);Debug.Log(text);}
}

 8、LocalTime and DeltaTime

Unity的Time. deltatime变量在SlowUpdate中不会返回正确的值,因为Unity的Time类对这个片段一无所知。可以使用Timing.DeltaTime代替。Unity中的默认Time类在大多数情况下都可以正常工作,但在SlowUpdate中无法正常工作。

9、其它的功能【Additional Functionality】

Timing对象中还包含三个辅助函数:CallDelayed、callcontinuous和callperiodic。

(1)CallDelayed: 在一定秒数后调用指定的动作。

(2)CallContinously:每帧连续调用动作,持续数秒。

(3)CallPeriodically:周期性地每隔“x”秒调用动作,持续数秒。

这三种功能都可以很容易地使用协程创建,但是这个基本功能最终被忽略了由于使用频繁,我们将其包含在基本模块中。


using System.Collections.Generic;
using UnityEngine;
using MEC;public class Test : MonoBehaviour
{private void Start(){// 2秒后启动_RunFor5Seconds。Timing.CallDelayed(2f, delegate{Timing.RunCoroutine(_RunFor5Seconds(Timing.RunCoroutine(Test01())));});// 使物体以每秒一个世界单位的速度向前推进,持续4秒。Timing.CallContinuously(4f, delegate {PushOnGameObject(Vector3.forward);}, Segment.FixedUpdate);// 尽量不要对callcontinuous进行闭包是非常重要的,因为这将导致每帧都进行GC分配。Timing.CallContinuously<Vector3>(Vector3.forward, 4f,vector => PushOnGameObject(vector), Segment.FixedUpdate);}private void PushOnGameObject(Vector3 amount){transform.position += amount * Time.deltaTime;}private IEnumerator<float> _RunFor5Seconds(CoroutineHandle waitHandle){Debug.Log("Yielding 5s..");yield return Timing.WaitUntilDone(waitHandle);Debug.Log("Starting 5 second run.");yield return Timing.WaitForSeconds(5f);Debug.Log("Finished 5 second run.");}private IEnumerator<float> Test01(){yield return Timing.WaitForOneFrame;Debug.Log("********");}
}

10、链式结构 【Fluid Architecture】

// 常规

Timing.RunCoroutine(_Foo().CancelWith(gameObject));

// MEC的链式

_Foo().CancelWith(gameObject).RunCoroutine();

请记住:与运行协程的其他方式一样,如果您忘记使用RunCoroutine,编译器不会报错,但它不会执行协程。当对Run的调用位于行尾时,这个事实可能有点难以记住。还要记住,这种流畅的语法可能会让其他习惯使用Unity默认协同程序的开发人员感到困惑,因为Unity的默认协同程序API不支持这种语法。

QA:

问:MEC有WaitForEndOfFrame函数吗?
它没有在MEC Free中实现,但MEC Pro有一个部分。
注意:关于WaitForEndOfFrame的实际作用有一些混淆。当你只是想屈服到下一帧时,WaitForEndOfFrame不是一个理想的命令,最好使用“yield return null;”。许多人在使用Unity的协程时使用WaitForEndOfFrame,因为这是他们在Unity的默认协程中最接近WaitForOneFrame的东西,他们没有意识到这可能会导致微妙的问题。MEC定义了常数Timing。WaitForOneFrame,所以在MEC中,如果你愿意,你可以使用显式变量名,而不会产生使用EndOfFrame可能导致的视觉故障和性能下降的可能性。

问:MEC有StopCoroutine的功能吗?
是的。它叫做Timing.KillCoroutines()。它可以接受前一个Timing返回的协程的句柄。RunCoroutine命令,或者它可以接受一个标记。
注意:KillCoroutine用于从不同的函数中停止协程函数。如果你想从协程的函数内部结束协程,那么最好的命令是“yieldbreak;”,这相当于在任何其他函数中调用“return;”。yield break更好的原因是因为KillCoroutine命令不能结束当前正在运行的协程函数,因此该函数将继续执行,直到下一个yield命令,但yield break没有这个问题。

问:MEC有StopAllCoroutines函数吗?
是的。Timing.KillCorutines()。如果你想暂时停止一切,你也可以使用Timing.PauseCorutines()和Timing.ResumeAllCorutines()。

问:MEC是否有一个函数使一个协程在另一个协程完成之前生成?
是的。在你想要持有的协程内部,你调用"yield return Timing.WaitUntilDone(coroutineHandle);"无论何时调用Timing.RunCoroutine,都会返回句柄。

问:MEC完全删除GC分配吗?
答:不是。MEC删除所有逐帧GC分配。(除非你在协程内部的堆上分配内存,但MEC无法控制这一点。)当协程第一次创建时,函数指针和传递给它的任何变量都被放在堆上,最终必须由垃圾收集器清理。这种不可避免的分配发生在Unity的协程和MEC协程中。MEC协程平均分配的垃圾确实比Unity协程少。

问:MEC协程总是比Unity协程内存效率更高吗,还是只有在特定情况下才如此?
答:MEC协程在所有情况下都比Unity协程产生更少的GC分配,除非你分配大字符串并将其作为协程的标记

案例:

void Start (){CoroutineHandle handle = 
Timing.RunCoroutine(_RunFor10Seconds());handle = Timing.RunCoroutine(_RunFor1Second(handle));Timing.RunCoroutine(_RunFor5Seconds(handle));}private IEnumerator<float> _RunFor10Seconds(){Debug.Log("Starting 10 second run.");yield return Timing.WaitForSeconds(10f);Debug.Log("Finished 10 second run.");}private IEnumerator<float> _RunFor1Second(CoroutineHandle
waitHandle){Debug.Log("Yielding 1s..");yield return Timing.WaitUntilDone(waitHandle);Debug.Log("Starting 1 second run.");yield return Timing.WaitForSeconds(1f);Debug.Log("Finished 1 second run.");}private IEnumerator<float> _RunFor5Seconds(CoroutineHandle
waitHandle){Debug.Log("Yielding 5s..");yield return Timing.WaitUntilDone(waitHandle);Debug.Log("Starting 5 second run.");yield return Timing.WaitForSeconds(5f);Debug.Log("Finished 5 second run.");}

 


http://www.ppmy.cn/news/358934.html

相关文章

从由器入手改善网络的安全性需要启用javascri

摘要&#xff1a;由器往往有不同的角色。 由器往往有不同的角色。例如&#xff0c;一般情况下&#xff0c;一个以太网端口连接到外部网络&#xff0c;四个端口提供到达局域网设备的互联网连接&#xff0c;无线发射装置向无线客户端提供访问。无线接口甚至可能提供多种SSID。 由…

互联网摸鱼日报(2023-06-13)

互联网摸鱼日报(2023-06-13) InfoQ 热门话题 数字化转型背景下&#xff1a;关于企业数据分析的趋势与预判 字节跳动全域数据治理平台负责人王慧祥确认出席 ArchSummit 深圳 2023开放原子全球开源峰会在北京成功举办 解决制造业效率、质量和成本的取舍问题&#xff0c;技术可…

windows7安装打印机提示“本地打印后台处理程序服务没有运行”

在win7系统中安装打印机经常会碰到以下问题。 解决方法&#xff1a; 1).在“运行”输入“services.msc”&#xff0c;弹出以下画面。 2).找到“Print Spooler ”双击&#xff0c;弹出下面画面&#xff0c;“启动类型”选择“自动”&#xff0c;点击“服务状态”的“启动”&…

无法启动计算机打印机服务程序,Windows10下使用打印机时提示打印后台处理程序服务没有运行怎么办...

在windows 10系统中&#xff0c;准备打印文件&#xff0c;在使用打印机的时候弹出了 windows 无法连接到打印机。 本地打印后台处理程序服务没有运行。请重新启动打印机后台处理程序或重新启动计算机。的提示&#xff0c;该怎么办呢&#xff1f; 出现这样的提示是由于windows 1…

计算机打印后台处理程序在哪里,Win7系统连接打印机出现本地打印后台处理程序服务没有运行怎么办...

最近有 解决方法&#xff1a; 1、打开 c:\windows\system32\spool\PRINTERS文件夹&#xff0c;点击右键-属性&#xff0c;取消只读属性、并删除PRINTERS文件夹中的所有文件(一般没有); 2、修改注册表 运行-regedit打开注册表 删除HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Cont…

xp计算机管理下的服务显示不出来,使用打印机出现无法打印XP电脑中后台程序服务没有运行修复...

现在只要网络我们很多的办公工具的使用中都是操作打印机的&#xff0c;那在win10电脑中想要修改电脑的设置都是在控制面板中来实现的&#xff0c;对于打印机的添加上是有小伙伴提问对于后台程序的服务没有运行的情况造成的&#xff0c;今天小编就来跟大家分享一下使用打印机出现…

计算机服务添加打印机服务,无法添加打印机报错后台程序服务没有运行的解决方法...

当添加打印机或是使用打印机时,系统报错“打印后台程序服务没有运行”,一般会发生在 Windows 2k、XP、2003这些NT内核系统上,出现此现象多是由于系统不稳定导致系统支持打印机的服务无法启用。该“打印后台程序服务”也就是“Print Spooler”服务,Windows2k、XP和2003系统支持打…

打印机后台服务器修复,修复win10出现“本地打印后台处理程序服务没有运行”的方法...

打印机无论是安装还是使用&#xff0c;只要我们一不小心就会出现很多的故障。今天小编要说到的故障时在win10系统中出现的&#xff0c;暂时不知道别的系统有没有。在使用打印机的时候经常会被系统提示“windows 无法打开“添加打印机”。”从提示或者我们就可以看出时由于打印机…