unity3d Coroutine Power


Example

Usage

If you have a long running operation that relies on the not-thread-safe Unity API, use Coroutines to split it over multiple frames and keep your application responsive.

Coroutines also help performing expensive actions every nth frame instead of running that action each frame.

Splitting Long-running Routines Over Multiple Frames

Coroutines help distribute long running operations over multiple frames to help keep up the framerate of your application.

Routines that paint or generate terrain procedurally or generate noise are examples that may need the Coroutine treatment.

for (int y = 0; y < heightmap.Height; y++) 
{
    for (int x = 0; x < heightmap.Width; x++)
    {
        // Generate pixel at (x, y)
        // Assign pixel at (x, y)
        
        // Process only 32768 pixels each frame
        if ((y * heightmap.Height + x) % 32 * 1024) == 0)
            yield return null; // Wait for next frame
    }
}

The code above is an easy to understand example. In production code it is better to avoid the per-pixel check that checks when to yield return (maybe do it every 2-3 rows) and to pre-calculate for loop length in advance.

Performing Expensive Actions Less Frequently

Coroutines help you perform expensive actions less frequently, so that it isn't as big a performance hit as it would be if performed every frame.

Taking the following example directly from the Manual:

private void ProximityCheck() 
{
    for (int i = 0; i < enemies.Length; i++) 
    {
        if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance)
                return true;
    }
    return false;
}

private IEnumerator ProximityCheckCoroutine() 
{
    while(true) 
    {
        ProximityCheck();
        yield return new WaitForSeconds(.1f);
    }
}

Proximity tests can be optimized even further by using the CullingGroup API.

Common Pitfalls

A common mistake developers make is accessing results or side effects of coroutines outside the coroutine. Coroutines return control to the caller as soon as a yield return statement is encountered and the result or side effect may not be performed yet. To circumvent problems where you have to use the result/side effect outside the coroutine, check this answer.