Coroutines

Unity logo

When working in Unity and you find yourself asking the following questions:

  • How can I make sure task A finishes before I do task B?
  • How do I delay a method by X seconds?
  • How can I wait for a condition to be met before continuing?
  • How can I wait for a response from a web request?
  • How do I prevent locking up the main thread while performing a computationally-intensive operation?

This is where Coroutines can help!

What are Coroutines?

Unlike normal C# functions, which are executed to completion within a single frame, Coroutines can:

  • Pause execution (yield) and return control to Unity
  • Continue execution in the next frame

Syntax

  • A Coroutine must return IEnumerator
  • Within the body, you must have a yield statement
  • To start a Coroutine: StartCoroutine(COROUTINE_FUNCTION()) or StartCoroutine("NAME_OF_COROUTINE")

How do you use Coroutines?

How to wait for X seconds

private void Start()
{
    StartCoroutine(TaskA(3));
}

private IEnumerator TaskA(int delay)
{
    Debug.Log("Task A started!");
    yield return new WaitForSeconds(delay);
    Debug.Log("Task A finished after " + delay + "seconds");
}

private void TaskB()
{
    Debug.Log("Task B!");
}

Result:

Console output showing Task A started and finished

How to run a computationally-intensive operation without locking up the main thread

private int _counter = 0;
private void Start()
{
    StartCoroutine(LongRunningTask());
}

void Update()
{
    if(_counter < 20)
    {
        Debug.Log("_counter: " + _counter);
    }
}

private IEnumerator LongRunningTask()
{
    // simulate a long running task
    while(_counter < 20)
    {
        _counter++;
        // return execution to main thread and
        // continue from here next frame
        yield return null;
    }
}

Result:

  • You’ll notice that 1 is printed twice. That’s because:
    • Start is called just before the first time Update is called
    • When Update is called, any previously yield-ed Coroutines are processed afterwards

Console output showing the counter incrementing across frames

Source

Unity script execution order diagram

Wait until a condition is met

private IEnumerator WaitUntilCounterIs(int value)
{
    yield return new WaitUntil(() => _counter == value);
    Debug.Log("Counter is now at: "+ value);
}

Result:

  • The Debug.Log will only be called once _counter equals value
  • The above would have the same performance as running while(_counter != value)

Considerations

  • Coroutines do not run on separate threads — they run on the main thread
  • You can stop a Coroutine using StopCoroutine(nameOfCoroutine/reference)
  • Where possible, you can use C# Tasks for asynchronous functionality