Unity

【Unity】同期・非同期処理の基礎と使い方

この記事について

この記事は私がゲーム制作・学習等で学んだ知識を元に非同期処理の使い方をわかりやすく説明していきます。

この記事でわかること

  • 同期処理と非同期処理の違い
  • コルーチン(Coroutine)を使った非同期処理
  • async/await を使った非同期プログラミング
  • スレッド(Thread)を使った処理

Unityの同期処理・非同期処理とは?

同期処理(Synchronous)の特徴

同期処理とは、1 つの処理が終わるまで次の処理を待つ仕組みです。
ゲームのメインスレッドで実行される処理は基本的に同期処理になります。

  • 処理が順番に実行されるので、デバッグが簡単
  • 計算負荷の高い処理を実行すると、ゲームがフリーズする

非同期処理(Asynchronous)の特徴

非同期処理とは、処理が終わるのを待たずに、他の処理を並行して実行する仕組みです。

  • ゲームが止まらず、スムーズに動作する!
  • 重い処理(データロード・ダウンロードなど)を別スレッドで処理できる!

非同期処理の種類と役割?

種類主な用途メリット注意点 / 制約
Coroutine(コルーチン)Unity特有の仕組み。IEnumerator を返すメソッドをStartCoroutine で実行。主に時間経過処理や待機処理に使用。シンプルに「待つ」や「毎フレーム処理」を書ける。Unityのフレームと同期して動作。マルチスレッドではなくメインスレッド上で動く。重い処理をやるとフリーズする。
async / await(C#非同期処理)C#の標準的な非同期処理。I/O処理(ファイル読み書き、Web通信など)でよく使う。コードが直感的に書ける。タスク完了を自然に待てる。Unityのメインスレッドと相性に注意。UI更新やUnity APIの呼び出しはメインスレッドで行う必要あり。
Thread(スレッド)CPUを使う重い処理(数値計算、画像処理など)をメインスレッドと分離して実行。メイン処理を止めずに並列処理が可能。UnityのAPIは呼べない。スレッド間のデータ共有に注意。

コルーチン(Coroutine)を使った非同期処理

コルーチン(Coroutine)とは?

Unityで非同期処理を行う最も一般的な方法は、コルーチン(Coroutine)です。
コルーチンを使えば、特定の処理を一時停止し、一定時間後に再開することができます。

コルーチン(Coroutine)の使い方については以下のサイトを参考にしてください。

async/awaitを使った非同期処理

async/await とは?

async/await使うとより直感的に非同期処理を記述できます。

  • コルーチンよりもスムーズな非同期処理が書ける!
  • I/O 処理(Web API・ファイル読み込み)に最適!

※あまり投稿者が理解をしていないので使い方は省略します。

using System.Threading.Tasks;
using UnityEngine;

public class AsyncTest : MonoBehaviour
{
    async void Start()
    {
        Debug.Log("処理A開始");

        await Task.Delay(2000); // 2秒待機(非同期)
        // await Task.Yield(); // フレームをまたいで待機

        Debug.Log("処理B再開");
    }
}

Thread(スレッド)を使った非同期処理

Thread(スレッド)とは?

Thread(スレッド)を使うと重い処理を別スレッドで実行し、メインスレッドをブロックしないようにできます。

  • 別スレッドで処理を実行し、メインスレッドの動作を止めない!

※あまり投稿者が理解をしていないので使い方は省略します。

using System.Threading;
using UnityEngine;

public class ThreadTest : MonoBehaviour
{
    private Thread workerThread;

    void Start()
    {
        workerThread = new Thread(HeavyProcess);
        workerThread.Start();
    }

    void HeavyProcess()
    {
        Debug.Log("重い処理開始");

        // ここで時間のかかる処理を実行(例: 数値計算)
        for (int i = 0; i < 100000000; i++)
        {
            // ダミー計算
            float value = Mathf.Sqrt(i);
        }

        Debug.Log("重い処理終了");
    }
}

SceneManager.LoadSceneAsync()で非同期ロード

SceneManager.LoadSceneAsync()」で非同期でシーンをロードし、進捗状況を表示可能になります。
SceneManagerについては以下のサイトを参考にしてください。

まとめ

・同期処理(Synchronous)は順番に実行され、ブロックされることがある!
・コルーチン(Coroutine)を使う、時間経過や非同期処理を簡単に実装可能
・スムーズなasync/await非同期処理が書ける