首页 文章

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

提问于
浏览
1

Edited the original question to elaborate: 我正在使用统一协程来执行一些重载操作 . 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 .

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

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

1 回答

  • 3

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

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

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

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

    2)协同程序没有返回值 . 你只需要 yield return null 跳过一个框架或者在你完成后休息 .

    一些笔记,

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

    这是关于"how do you call 'the result of' coroutines more than once"的讨论,这与你所要求的有关 . (当我自己问这个问题时......就出现了......我当然没有意识到!)

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

    最后

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

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

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

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

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

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

    唐't forget, all you'说的是"it is code that will run each frame" - 仅此而已 . (完全像 Update() . )

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

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

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


    要绝对清楚.....

    只是重复同样的观点,

    public class TaskScheduler : MonoBehaviour
    

    同样请注意协同程序

    根本没有连接到“任务”或“线程”

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

    每帧运行一些东西的方法 .

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

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

    (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与"tasks"或"threads"没有任何联系 - 这就是你所得到的 . 协同程序就是你如何访问Unity中的"frame system" . 对于统一线程,请查看许多线程池辅助类型脚本或系统之一,这很方便 .

相关问题