什么是嵌套协同程序生成的代码

编辑原始问题详细说明:我正在使用统一协程执行一些重载操作。 Unity是一个游戏引擎,代码在帧内运行。 如果操作是密集的,则必须在协同程序中完成,否则帧需要很长时间才能完成。 协程方法就是DoTasks 。 如果您不熟悉Unity引擎,它们与迭代器类似。

首先,我必须说这些代码按照它们应该的方式工作。 问题在于堆分配。 那说我会解释代码的作用。 当调用Init ,它启动协程并进入DoTask然后进入foreach以迭代currentTask.Execute()然后进入obj.CreateCellGosTask进行迭代。 现在我们遇到的第一个收益率回报,foreachs链将结果返回到初始协程(即StartCoroutine(DoTasks()))并且我们已经完成了框架。 在下一帧中,代码在执行的最后一行之后的链中继续。 这是行为,并且工作正常。

 public class TaskScheduler : MonoBehaviour { private static volatile Task currentTask; public void Init(){ StartCoroutine(DoTasks()); //Starts the coroutine } private IEnumerator DoTasks() { while(true){ foreach (object b in currentTask.Execute()) { yield return b; //Do something } } } public class Task { private Cell cell; public IEnumerable Execute() { foreach (object b in cell.CreateCellGosTask()){ yield return b; // Do something } } 

收益率的回报率为零。 在所有嵌套迭代器中,它都返回null。

问题是关于堆分配。 由于编译器生成实现IEnumerable的隐藏 (我认为),代码会产生垃圾。 不幸的是,垃圾收集在统一中是一个大问题。

最终目标是在foreach链中实现零堆分配(StartCoroutine并不重要)。那么问题究竟是编译器生成的代码以及它如何创建Enumerable和Enumerator类? 我指的是DoTasksExecute的确切生成代码。 然后我可以输入完全相同的代码并创建并返回结构而不是类。

(您可能更喜欢在下面用大写字母跳过我的简短说明!)

我可能会误解你要做的事,但是,

1)协同程序与线程完全无关。

(Unity根本不使用线程。如果你需要创建一个线程(比如说是处理),你需要使用一个线程管理器(有许多可用的,或者自己编写)……但它与协同程序无关。)

2)协同程序没有返回值。 你只需要yield return null可以跳过一个帧或者在你完成时中断。

一些笔记,

http://answers.unity3d.com/answers/966469/view.html http://answers.unity3d.com/answers/1119978/view.html

这是一个关于“你怎么称呼”冠冕不止一次’的结果”的讨论,这与你所要求的有关。 (当我自己问这个时出现了…… https://stackoverflow.com/a/34550206/294884 …我当然没有意识到!)

我希望这在某种程度上有所帮助!

最后

4)你不能以任何有意义的方式嵌套协程。

你只是“开始另一个新的协程”。 你懂? 你所指的只是“等到”一个完成再运行另一个,或者“继续”并一次开始几个。

谷歌100对此的讨论.. http://answers.unity3d.com/questions/14081/nested-coroutines.html或http://answers.unity3d.com/answers/515074/view.html

你无法以任何方式有意义地“嵌套协同程序”。

想象一下,你有一张带有挡水板的厨房桌子。 你开始跑秒表。 如果由于某种原因你想要,你可以开始并运行其中许多。 (他们中的一些人“可能会自己开始其他人”,或者他们可能会从其他地方开始。)

但是没有“嵌套”它们的概念,它们只是在那里运行的秒表。

别忘了,你所说的只是“它是运行每一帧的代码” – 仅此而已。 (完全像Update() 。)

再一次—–我感觉到你真正追求的是Unity中的线程,这可以小心实现。 示例—

http://answers.unity3d.com/answers/443604/view.html

事实上,你有点想要与整个框架系统无关,也没有协同作用,听起来像你需要一个线程,也许用数学计算。


要绝对清楚…..

只是重复同样的观点,

 public class TaskScheduler : MonoBehaviour 

同样请注意协同程序

根本没有“任务”或“线程”的联系

一个“协程”只不过是这个:

一种在每一帧运行某种东西的方法。

就是这样。 如您所知,游戏引擎环境为您提供了“每帧…”概念运行循环。

让我们说无论出于什么原因(比如说……移动一个物体,动画怪物)你想要“每一帧”做一些事情。 在Unity中有两种方法可以访问该function。

(1)只需使用Unity为您提供的Update()quasifunction:

 Update() { if ( moveTheDinosaur ) { // code here will run every frame, // frames are beautifully managed by Unity { 

(2)只使用一个协程:

 launch coroutine showDinosaur coroutine showDinosaur() { while(true) { // code here will run every frame, // frames are beautifully managed by Unity yield return null; // the formulaic line "yield return null" // indicates to the MonoBehaviour engine that's // the end of your processing this frame; // (Implementation details are unknown to us // and irrelevant) } } 

请注意 – 事实上 – 如果你是一个经验丰富的程序员,一旦你使用Unity超过一天,你会发现“更新()”的事情通常是完全愚蠢的,你倾向于使用你自己的协程来做某事每一帧。 (当然,“Update()”对于快速演示或测试代码时的任何内容都很方便。)

再说一遍,couroutines与“任务”或“线程”没有关系 – 我想,当然我可能错了 – 这就是你所得到的。 协同程序就是你如何访问Unity中的“框架系统”。 对于统一线程,请查看许multithreading池辅助类型脚本或系统之一,这很方便。