Unity async / coroutine

created 1. November. 2024

In Unity coroutines and async basically do the same. But coroutines work better with Unity, while async is more powerfull.

Run function asynchronously with delay

Coroutine Async
public void Start()
{
    StartCoroutine(CountdownCoroutine(10));
}

public IEnumerator CountdownCoroutine(int value)
{
    int counter = value;
    var waitOneSecond = new WaitForSeconds(1.0F);

    while (counter > 0)
    {
        Debug.Log($"Countdown: {counter}");
            
        yield return waitOneSecond;
        counter--;
    }
}

Since the new WaitForSecond() call creates a new object every time it is run, it is a good idea to cache this object once at the beginning and then re-use it in every loop, like this example does with the waitOneSecond variable.

public void Start()
{
    CountdownAsync(10);
}

public async void CountdownAsync(int value)
{
    int counter = value;

    while (counter > 0)
    {
        Debug.Log($"Countdown: {counter}");
            
        await Task.Delay(1000);
        counter--;
    }
}

Wait for return data

Coroutine Async

/* Not directly supported */
        

A coroutine cannot directly return data, because it is already returning the IEnumerator.

You can work around this limitation by writing the result into a global variable, but this is not ideal since it hides what the method is actually doing.

public async Start()
{
    int result = await CountdownAsync();
    
    Debug.Log($"Result: {result}");
}
            
public async Task<int> CountdownAsync(int value)
{
    int counter = value;

    while (counter > 0)
    {
        counter--;
        await Task.Yield();
    }

    return Random.Range(0, 1000);
}

Run functions asynchronously one after the other

Coroutine Async
public IEnumerator Start()
{
    yield return CountdownCoroutine(10);
    yield return CountdownCoroutine(20);
    yield return CountdownCoroutine(30);
}

public IEnumerator CountdownCoroutine(int value)
{
    int counter = value;

    while (counter > 0)
    {
        counter--;
        yield return null;
    }
}
public async Start()
{
    await CountdownAsync(10);
    await CountdownAsync(20);
    await CountdownAsync(30);
}

public async Task CountdownAsync(int value)
{
    int counter = value;

    while (counter > 0)
    {
        counter--;
        await Task.Yield();
    }
}

Run functions asynchronously, but wait for all to finish

Coroutine Async

/* Not directly supported */
        
public async Start()
{
    List<Task> tasks = new List<Task>();

    tasks.Add(Countdown(10));
    tasks.Add(Countdown(20));
    tasks.Add(Countdown(30));

    await Task.WhenAll(tasks);
}

public async Task Countdown(int value)
{
    int counter = value;

    while (counter > 0)
    {
        counter--;
        await Task.Yield();
    }

    Debug.Log($"Finish {value} - 0");
}