StartCoroutine and Yield

Hi, I am new to Unity and have little confusion in understanding StartCoroutine method and Yield statement. I have few questions:

  • What is the difference between yield break; and yield return null; and yield return new WaitForEndOfFrame();
  • What does yield return 1; mean?
  • Does StartCoroutine initiate a new thread or its just a technique to execute code asynchronously within the main thread?
  • What is the use of Nested Coroutines and What are its benefits?

Thank you,

4 Likes
  1. “yield break” breaks the Coroutine (it’s similar as “return”). “yield return null” means that Unity will wait the next frame to finish the current scope. “yield return new” is similar to “yield return null” but this is used to call another coroutine.
public IEnumerator MyFunctionCoroutine() {
    if (myVar == null) {
        // Do not continue the coroutine.
        yield return break;
    }

    while (Time.time < myDelay) {
        // Come here the next frame
        yield return null;
    }
}
  1. I have no idea, but you can not get the value returned by a Coroutine. I think it’s for internal purpose.
  2. Unity doesn’t use thread (and you shouldn’t use thread with Unity components), as you said, it just temporarily stops the current scope and continues it the next frame. This is really useful when you want to wait an animation to finish (because it doesn’t block the program, like a simple “while(true){};” does).
  3. Do not know !
2 Likes

(Grumpy because I’d written a long reply to this which Firefox just lost. Shorter retyped summary follows!)

3.) Neither. A coroutine is a function that can be “paused”, and then resume execution from where it left off in a subsequent frame. They still run in the main thread, but are useful for spreading operations over several frames.

1.) and 2.) The Yield statement marks the point at which the coroutine “pauses”. Depending on what follows the yield determines what value is returned to the enumerator object, and if and when the coroutine will continue.

  • yield break, rather like a normal “return”, breaks out of the iterator function early - any subsequent code will not be executed.

  • yield return null, yield return 1, and yield return new WaitForEndofFrame are similar, but subtly different. They all return control to the calling function, and schedule the coroutine to continue execution in the next frame. The difference is in at what point in the next frame the coroutine will next be executed. Take a look at the lifecycle on this page: Unity - Manual: Order of execution for event functions - which illustrates the following:

  • WaitForEndOfFrame will schedule the coroutine to be run at the end of the frame just before rendering.

  • WaitForFixedUpdate (which you didn’t mention) will schedule the coroutine to run as part of the physics update step

  • WaitForSeconds (which you didn’t mention) schedules the coroutine to continue after the given number of seconds has elapsed.

  • Any other yield value, including 1, null, true, false, or “bananas” will continue the coroutine on the next frame as part of the standard game logic Update step.

4.) Not sure, never used them. Sounds like a recipe for spaghetti code disaster :slight_smile:

6 Likes

Thank you Sbizz and tanosimi for your great explanations. What I understand is:

  • yield return null will resume execution immediately after next Update() and yield return WaitForEndOfFrame() will resume after next Update() but before rendering starts. While yield break just stops the coroutine and returns.
  • yield return 1 is nothing just a just a clone of yield return null. (So it may never be used).
  • Coroutines are niether new thread nor async. They are just like do a task A in same thread synchronously untill you gets yield statement and when yield is executed, wait as per yield statement says while doing other tasks and then go back to coroutine and finish the remaining coroutine.
  • If I understood the 3 correctly, then nested coroutines means nothing and should always be avoided in fact should not be used.

I’m sorry, but could someone post this “nested coroutine” thingy? I’ve never heard of this phrase.

I have no idea what are the purposes of this thing, but I have seen it on forum somewhere. It will be something like,

IEnumerator Func2()
{
     //some code here
     yield return StartCoroutine (Func1());
     //some code here
}

or

IEnumerator Func2()
{
     //some code here
     StartCoroutine (Func1());
     //some code here
}

where Func2() is also called through StartCoroutine.

Here is small example of how nested coroutines work:

// These are written without compiling so they may not compile!
void Start()
{
   StartCoroutine(SomeSequence());
}
IEnumerator SomeSequence()
{
   Debug.Log("Start some sequence");
   yield return StartCoroutine(ActionOne());
   Debug.Log("In the middle of some sequence");
   yield return StartCoroutine(ActionTwo());
   Debug.Log("End some sequence");
}
IEnumerator ActionOne()
{
   Debug.Log("Start action one");
   yield return new WaitForSeconds(3f);
   Debug.Log("End action one (waited 3 seconds)");
}
IEnumerator ActionTwo()
{
   Debug.Log("Start action two");
   yield return new WaitForSeconds(1f);
   Debug.Log("End action two (waited 1 second)");
}

Output in the console would be like this:

Start some sequence
Start action one
End action one (waited 3 seconds)
In the middle of some sequence
Start action two
End action two (waited 1 second)
End some sequence

So the main thing to notice is that if you start a new coroutine within a coroutine (with “yield return StartCoroutine()”) it will wait that the started coroutine is finished before the coroutine that started it continues.

I hope that helps you guys!

-hp

4 Likes

Thanks MentalMoustache for explanation, but this raise one more question in my mind:
If outer coroutine will resume its execution once inner coroutine ends completely, so why should we call inner coroutine? Same execution order can be achieved with single coroutine, if we just replace “yield returnStartCoroutine(ActionOne());” with its implementation.
In short, I can’t understand use/benefit of nested coroutine.

The advantage of nested coroutines is that you can organize your code however you want. You can have conditionals, loops or whatever you want in the outer coroutine which then calls the inner coroutines that may themselves have that kind of structure.

1 Like

Right, that makes some sense. We may, then, say that nested coroutines are just for organizing your code in modules. :slight_smile: