what is the code generated by nested coroutines
Edited the original question to elaborate: I'm using unity coroutines to perform some heavy duty operations. Unity is a game engine and codes are run within frames. If an operation is intensive, it has to be done in coroutines otherwise it takes a long time for a frame to complete. Here the coroutine method is DoTasks
. If you are not familiar with the unity engine, they are similar to iterators.
First of all I have to say these codes work as they are supposed to do. The problem is with heap allocation. That said I will explain what the codes do. When Init
is called it starts the coroutine and goes into DoTask
and then goes inside foreach
to iterate currentTask.Execute()
and then goes into obj.CreateCellGosTask
to iterate. now the first yield return we encounter, the chain of foreachs return the result to the initial coroutine(namely StartCoroutine(DoTasks()) ) and we're done for the frame. On next frame the code continues in the chain right after the last line that was executed. This is the behaviour and works fine.
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
}
}
What the yield returns is of zero importance. In all nested iterators it yield returns null.
The problem is about heap allocation. The code creates garbage due to the fact that the compiler generates hidden classes implementing IEnumerable (I think). Unfortunately Garbage collection is a big deal in unity.
The ultimate goal is to zero heap allocation in foreach chain (StartCoroutine is not important).So the question is exactly what code the compiler generates and How it creates Enumerable and Enumerator classes? I mean the exact generated code of DoTasks
and Execute
. Then I could just type the exact same code and create and return a struct instead of a class.
(You may prefer to skip to my short explanation in large letters below!)
I may misunderstand what you're trying to do, but,
1) Coroutines have absolutely nothing to do with threads.
(Unity does not use threads at all. If you need to make a thread (say for processing) you need to use a thread manager (there are many available, or write your own) ... but it is unrelated to coroutines.)
2) Coroutines have no return value. You just yield return null
to skip a frame or break when you're done..
Some notes,
http://answers.unity3d.com/answers/966469/view.html http://answers.unity3d.com/answers/1119978/view.html
that was a discussion about "how do you call 'the result of' coroutines more than once" which is kind of related to what you're asking. (That came up when I myself was asking this ... https://stackoverflow.com/a/34550206/294884 ... which I certainly did not realise!)
I hope this helps in some way!
Just finally
4) You can't nest coroutines in any meaningful way.
You're just "starting yet another new coroutine". You know? What you're referring to is either just "waiting until" one finishes to run another one, or, "going ahead" and starting a few up at a time.
Google 100s of discussions on this .. http://answers.unity3d.com/questions/14081/nested-coroutines.html or http://answers.unity3d.com/answers/515074/view.html
You can't meaningfully "nest coroutines" in any way.
Imagine you have a kitchen table with stopwatches sitting on it. You start and run a stopwatch. If for some reason you want to, you can start and run many of them. (Some of them "may start the others" themselves, or they may be started from elesewhere.)
But there's no concept of "nesting" them, they're just stopwatches running there.
Don't forget, all you're saying is "it is code that will run each frame" - nothing more than that. (Exactly like Update()
.)
Once again ----- I get the feeling that what you're actually after is threading in Unity, which can be achieved with care. Example ---
http://answers.unity3d.com/answers/443604/view.html
Indeed you sort of want nothing to do with the whole frame system, nor coroutines, sounds like you need a thread perhaps with a math calculation.
To be absolutely clear .....
Just to repeat the same point,
public class TaskScheduler : MonoBehaviour
Note that coroutines very simply
have no connection, at all, to "tasks" or "threads"
a "coroutine" is nothing more than this:
a way to run something every frame.
That's all it is. As you know, the game engine environment gives you a "each frame..." concept run loop.
Let's say for whatever reason (say .. moving an object, animating a monster) you want to do something "every frame". There are two ways to access that ability in Unity.
(1) Just use the Update() quasifunction which Unity provides for you:
Update()
{
if ( moveTheDinosaur )
{
// code here will run every frame,
// frames are beautifully managed by Unity
{
(2) Just use a coroutine:
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)
}
}
Note that - indeed - if you're an experienced programmer as soon as you use Unity for more than a day, you realise the "Update()" thing is generally speaking completely silly, you tend to just use your own coroutine to do something each frame. (Of course, "Update()" is handy just for quick demos or whatever when testing code.)
Again to reiterate, couroutines just have no connection to "tasks" or "threads" -- which -- I guess, of course I may be wrong -- is what you're getting at. Coroutines are simply how you access the "frame system" in Unity. For threading in unity, look in to one of the many threading-pool-helper type scripts or systems available, which are convenient.
链接地址: http://www.djcxy.com/p/53172.html上一篇: 为什么协程会改变变量的值?
下一篇: 嵌套协程生成的代码是什么