C# - 同期処理・非同期処理(Thread、Task)
初めに
プログラミングには、同期処理と非同期処理という2つの処理方法があります。この記事では、同期処理と非同期処理がそれぞれどのようなものであるか、そしてC#においてそれぞれを実行する方法についてまとめます。
Index
同期処理
同期処理とは
同期処理とは、
複数の処理を実行する際、1つずつ上から順番に実行する処理のこと
です。いわゆる、順次処理のことで、通常の処理は同期処理だと思ってよいでしょう。
同期処理では、次のようなソースコードでは、Method1 が終わってから Method2 が実行されます。
Method1(); Method2();
同期処理のメリット
- ソースコードの上から順に読んでいくだけなので、どのように進んでいくか読むことが容易
- タスクが完了するのを待つことで、結果を確実に取得することができる
同期処理のデメリット
- 処理同士でタイミングを合わせる必要がある場合、ある処理が完了するまで別の処理は完全に停止する
非同期処理
非同期処理とは
非同期処理とは、
複数の処理をする際に順番を待たないで次の処理が実行されます処理方法のこと
です。
Unity においては、コルーチンは非同期処理にあたります。
コルーチンについては、次のリンク先に記事をご覧ください。
例えば、次のようなソースコードを実行すると、Start は上から処理されます。Test1 はコルーチンなので、Test1 の終了を待たずに Test2 が開始されます。同様に Test2 もコルーチンなので、Test2 の終了を待たずに "Start終了" のログが表示されています。
using System.Collections; using UnityEngine; public class Test : MonoBehaviour { void Start() { Debug.Log("Start開始"); StartCoroutine(Test1()); StartCoroutine(Test2()); Debug.Log("Start終了"); } IEnumerator Test1() { Debug.Log("Test1開始"); yield return null; // 1フレーム待機 Debug.Log("Test1終了"); } IEnumerator Test2() { Debug.Log("Test2開始"); yield return null; // 1フレーム待機 Debug.Log("Test2終了"); } }
(実行結果)
非同期処理のメリット
- 複数の処理を並行して行えるので、パフォーマンスの向上が見込める
非同期処理のデメリット
- 制御が複雑になる
- 実行中のタスクを監視し、完了したタスクからの結果を収集するための追加のコードが必要なことがある
C# における非同期処理
Thread
Thread は直訳では「糸、筋道」であり、プログラミングでは、一連の処理の流れを意味します。複数の処理を並行して行うものをマルチスレッドといいます。
C# では Thread クラスを使うことで、非同期処理をすることができます。
Thread は次のように使用します。
(Thread クラスの基本的な使い方)
なお、非同期処理をする中で、他のスレッドを待つ必要がある場合があります。その場合、Thread クラスにある sleep 関数と Join 関数を使用します。
関数 | 説明 |
---|---|
Thread.Sleep | 指定したミリ秒数の間、現在のスレッドを中断する |
Thread.Join | このインスタンスが表すスレッドが終了するまで、呼び出し元のスレッドをブロックする |
(例)
using System.Threading; //Threadクラスを使うために追加 using UnityEngine; public class ThreadTest : MonoBehaviour { void Start() { //Threadクラスの構築 //ThreadStartを使い, 使いたい関数を指定する Thread thread = new Thread(new ThreadStart(Method1)); //Threadの開始 thread.Start(); //Threadが終わるまで(今回は Method1 が終わるまで)待機 thread.Join(); Method2(); } void Method1() { Debug.Log("Method1開始"); Thread.Sleep(1000); //1000ミリ秒待機 Debug.Log("Method1終了"); } void Method2() { Debug.Log("Method2開始"); Thread.Sleep(500); //500ミリ秒待機 Debug.Log("Method2終了"); } }
(実行結果)
Thread クラスの関数は下のドキュメントをご覧ください。
Task
Task クラスを使用しても非同期処理を行うことができます。
Task クラスを使用した非同期処理は基本的には次のように行います。
(Task クラスの基本的な使い方)
- Task クラスを使うために、名前空間に using System.Threading.Tasks; を記述する
- 使いたい関数を記述する
- Task.Run 関数を使い、実行する
よく使う処理は次の通りです。
(Task クラスでよく使う関数、変数)
- Run 関数で実行
- Wait 関数で処理が終わるまで待機
- Delay 関数で指定した数ミリ秒待機
- Result で返り値を受け取れる
(例)
using System.Threading.Tasks; //Taskクラスを使うために追加 using UnityEngine; public class ThreadTest : MonoBehaviour { void Start() { //処理したい関数に返り値がない場合 Task task1 = Task.Run(Method1); //Taskの実行 task1.Wait(); //task1(今回はMethod1)が終了するまで待機 //処理したい関数の返り値がstringの場合 Task<string> task2 = Task.Run(Method2); //Taskの実行 string text = task2.Result; //返り値の受け取り Debug.Log($"task2から返ってきたテキスト{text}"); } void Method1() { Debug.Log("Method1開始"); Task.Delay(1000); //1000ミリ秒待機 Debug.Log("Method1終了"); } string Method2() { Debug.Log("Method2開始"); Task.Delay(500); //500ミリ秒待機 string text = "このテキストを返す"; return text; } }
(実行結果)
Task クラスで使う関数、変数は下のドキュメントをご覧ください。
learn.microsoft.com
最後に
- 同期処理とは、複数の処理を実行する際、1つずつ上から順番に実行する処理のこと
- 非同期処理とは、複数の処理をする際に順番を待たないで次の処理が実行されます処理方法のこと
- C# の非同期処理の方法として、Thread クラスを使う方法と Task クラスを使う方法がある