- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
编辑原始问题以详细说明:我正在使用 unity 协程来执行一些繁重的操作。 Unity 是一个游戏引擎,代码在框架内运行。如果一个操作是密集型的,它必须在协程中完成,否则一个框架需要很长时间才能完成。这里协程方法是DoTasks
。如果您不熟悉 unity 引擎,它们类似于迭代器。
首先,我必须说这些代码按预期工作。问题在于堆分配。也就是说,我将解释代码的作用。当调用 Init
时,它会启动协程并进入 DoTask
,然后进入 foreach
以迭代 currentTask.Execute()
然后进入obj.CreateCellGosTask
进行迭代。现在我们遇到第一个 yield return,foreach 链将结果返回到初始协程(即 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 返回是零重要性。在所有嵌套迭代器中,它 yield 返回 null。
问题是关于堆分配的。由于编译器生成实现 IEnumerable 的隐藏类(我认为),因此代码会产生垃圾。不幸的是,垃圾收集在统一中是一件大事。
最终目标是将foreach链中的堆分配归零(StartCoroutine并不重要)。所以问题是编译器生成什么代码以及它如何创建Enumerable和Enumerator类?我的意思是 DoTasks
和 Execute
的确切生成代码。然后我可以键入完全相同的代码并创建并返回一个 struct 而不是一个类。
最佳答案
(您可能更愿意跳到下面我用大写字母的简短解释!)
我可能误解了你的意思,但是,
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) 您不能以任何有意义的方式嵌套协程。
您只是在“启动另一个新协程”。你知道?您指的是要么只是“等到”一个完成运行另一个,要么“继续”并一次启动几个。
Google 对此进行了 100 多次讨论.. http://answers.unity3d.com/questions/14081/nested-coroutines.html或 http://answers.unity3d.com/answers/515074/view.html
您不能以任何方式有意义地“嵌套协程”。
假设您有一张厨房 table ,上面放着秒表。您启动并运行秒表。如果出于某种原因你想要,你可以启动并运行其中的许多。 (其中一些“可能会启动其他”自己,或者可能会从其他地方启动。)
但是没有“嵌套”它们的概念,它们只是跑在那里的秒表。
不要忘记,您所说的只是“它是将运行每一帧的代码”——仅此而已。 (与 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()”仅用于快速演示或测试代码时的任何其他内容。)
再次重申,协程与“任务”或“线程”没有任何联系——我想,当然我可能是错的——这就是你想要的.协程只是您访问 Unity 中的“框架系统”的方式。对于统一线程,请查看许多可用的线程池助手类型脚本或系统之一,它们很方便。
关于c# - 嵌套协程生成的代码是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34783651/
在我的设置中,我试图有一个界面 Table继承自 Map (因为它主要用作 map 的包装器)。两个类继承自 Table - 本地和全局。全局的将有一个可变的映射,而本地的将有一个只有本地条目的映射。
Rust Nomicon 有 an entire section on variance除了关于 Box 的这一小节,我或多或少地理解了这一点和 Vec在 T 上(共同)变体. Box and Vec
我是一名优秀的程序员,十分优秀!