嵌套协程生成的代码是啥

Posted

技术标签:

【中文标题】嵌套协程生成的代码是啥【英文标题】:what is the code generated by nested coroutines嵌套协程生成的代码是什么 【发布时间】:2016-04-19 10:17:08 【问题描述】:

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

首先,我必须说这些代码按应有的方式工作。问题在于堆分配。也就是说,我将解释代码的作用。当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
    

收益回报的重要性为零。在所有嵌套迭代器中,它 yield 返回 null。

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

最终目标是在 foreach 链中零堆分配(StartCoroutine 并不重要)。所以问题是编译器生成的代码到底是什么以及它如何创建 Enumerable 和 Enumerator 类?我的意思是DoTasksExecute 的确切生成代码。然后我可以输入完全相同的代码并创建并返回一个 struct 而不是一个类。

【问题讨论】:

您需要提供代码的minimal reproducible example。 你会发现这个视频有助于更好地理解协程youtube.com/watch?v=ciDD6Wl-Evk。您也可以使用反编译器并查看 UnityEngine.dll 的内部 @DmitryMorgachev 这与课程无关。该类是在运行时生成的,我唯一的线索是它是一个 IEnumerable。另外我对IL一无所知,所以我无法理解实际的实现是什么 嗨,莫特萨。正如我在下面解释的那样,协程很可能根本不是你想要的。像您这样经验丰富的工程师,对于 Unity 的新手,瞄准诸如此类的错误点是很常见的......一个可能的原因可能是 Unity 令人难以置信地缺乏对文档中任何内容的解释! :O 【参考方案1】:

(您可能更愿意跳到下面我用大写字母进行的简短解释!)

我可能会误解你想要做什么,但是,

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

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

2) 协程没有返回值。完成后,您只需 yield return null 跳过一帧或中断..

一些笔记,

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

那是关于“你如何多次调用‘协程’的结果”的讨论,这与你所问的有点相关。 (当我自己问这个问题时就出现了……https://***.com/a/34550206/294884……我当然没有意识到!)

我希望这会有所帮助!

终于

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

你只是在“开始另一个新的协程”。你懂的?您所指的要么只是“等到”一个完成运行另一个,要么是“继续”并一次启动几个。

Google 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 中有两种方法可以访问该功能。

(1) 只需使用 Unity 为您提供的 Update() 准函数即可:

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()”这个东西通常来说完全是愚蠢的,你倾向于只使用自己的协程每帧做一些事情。 (当然,“Update()”仅用于快速演示或测试代码时非常方便。)

再次重申,couroutines 与“任务”或“线程”无关——我想,当然我可能错了——这就是你要说的.协程只是您在 Unity 中访问“框架系统”的方式。对于统一线程,请查看许多可用的线程池助手类型脚本或系统之一,这很方便。

【讨论】:

好吧,感谢您提供冗长而全面的答案。实际上,算法的一些重要部分是多线程的,但统一 API 仍然是单线程的,因此无法进行大型操作,例如设置地形高度图或在多线程上下文中创建对撞机,而且线程时间切片在 android 设备上有点大。这不是愤怒的小鸟,它是一个开放世界的项目,需要 1 年时间。为了在统一的主线程上挤压每一毫秒,我必须使用嵌套协程。否则我无法很好地控制分块密集型任务。 嗨,莫特萨。当然,如果你有一些处理要做,使用线程。我建议你抓住所有的线程包,例如assetstore.unity3d.com/en/#!/content/20857 Coroutines 与线程无关并且不会以任何方式帮助你。请注意,所有协程都只在主线程上运行,所以这绝对不是您想要的。 这是最好的 Unity 工程师 answers.unity3d.com/answers/357040/view.html 的一篇出色的文章,其中有人对协程 V 线程感到困惑,这解释了如何完美地使用线程。 请注意,没有嵌套协程之类的 我喜欢您提出的整个概念,并且您提供的链接完全相关。但是有些工作必须在主线程中完成,即地形的 SetHeight 和 SetAlphamap,而且它们非常昂贵。当然,有一种方法可以避免嵌套协程,但是这种模式比任何替代方案都简单得多,并且不会干扰您当前的方法。您只需将它们设为 IEnumerable 并使用 foreach 调用它们。我把需要在主线程上完成的所有事情都称为“任务”。这些任务有时是复杂的方法调用链。我在 TaskScheduler 类上启动一个任务。和

以上是关于嵌套协程生成的代码是啥的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中的字节码是啥?

perl 解释器的状态码是啥意思?

序列码是啥

微信有弹窗的啥码

程序开发中yield是啥,怎么用?

键盘箭头的扫描码是啥? (右、左、下、上)