Reactive Extensionsを使用したUnityでのマルチスレッド





この記事では、Unityを使用してマルチスレッドモバイルゲームを開発する際に発生する主な問題と、 UniRx (Unityのリアクティブ拡張)を使用してそれらを解決する方法について説明します。



この記事は2つの部分で構成されています。 1つ目は「最小」のマルチスレッドに特化しており、アクセス可能な言語でスレッドとスレッドの作成方法、スレッドの同期について説明しています。 2番目の部分は、リアクティブエクステンション、その配置、動作原理、および適用方法に専念します。



Unityでスクリプトを記述するための言語の1つはアプリケーションを開発するC#であるため、すべてのコードはその上でのみ記述されます。 マルチスレッドおよびリアクティブ拡張の原則を深く理解するには、マルチスレッドの基本リアクティブ拡張とは何かを読むことをお勧めします。 読者がこのトピックに精通している場合、最初のセクションはスキップできます。



最小のマルチスレッド



マルチスレッドアプリケーションは、複数のタスクを別々のスレッドで同時に実行するアプリケーションです。 マルチスレッドを使用するアプリケーションは、ユーザーインターフェイスがアクティブのままであるため、ユーザーのアクションにより迅速に応答しますが、集中的なプロセッサー作業を必要とするタスクは他のスレッドで実行されます。 Monoを使用するC#マルチスレッドアプリケーションは、キーワードThread、ThreadPool、および非同期デリゲートを使用して開発されます。



構成例を使用して、マルチスレッドアプリケーションを見てみましょう。 各労働者が他の労働者と同時にその職務を遂行すると仮定します。 たとえば、1つは床を洗い、もう1つは窓を洗います。 (そして、これはすべて同時に起こります)。 これらは私たちの流れです。







スレッド-既存のアプリケーション内に新しいスレッドを作成できるクラス。

非同期デリゲート-呼び出されたメソッドと同じシグネチャで定義されたデリゲートを使用して、メソッドを非同期的に呼び出します。 非同期メソッド呼び出しの場合、BeginInvokeメソッドを使用する必要があります。 このアプローチでは、デリゲートはプールからストリームを取得し、その中のコードを実行します。



ThreadPool-「オブジェクトプール」パターンの実装。 その意味は、効果的なフロー管理::作成、削除、作業の割り当てです。 建設の例えに戻ると、ThreadPoolは建設現場の建設業者の数を管理し、それぞれにタスクを割り当てる職長です。







スレッド同期ツール



C#言語は、スレッドを同期するためのツールを提供します。 これらのツールは、ロックおよびモニターの形式で表示されます。 これらは、コードブロックの実行が複数のスレッドによって同時に実行されないようにするために使用されます。 ただし、注意点が1つあります。 これらのツールを使用すると、デッドロック(デッドロックスレッド)につながる可能性があります。 これは次のように発生します。スレッドAはスレッドBが制御を返すのを待ち、スレッドBはスレッドAがブロックされたコードを実行するのを待ちます。 したがって、マルチスレッドとスレッドの同期は注意して使用する必要があります。



UnityのUnityスレッドの問題



シングルスレッドアプリケーションの開発時に直面する主な問題は、メインスレッドでの複雑な操作に起因するUIフリーズです。 Unityにはタスクを並列化するメカニズムがあり、コルーチン(コルーチン)の形式で表示されますが、1つのスレッドで動作し、コルーチンで「重い」何かを実行する場合-こんにちは、フリーズ。 メインスレッドで関数の並列実行に満足している場合は、コルーチンを使用できます。 複雑なことは何もありません。Unityのドキュメントでは、このトピックは非常によくカバーされています。 ただし、コルーチンはUnityで次のように動作するイテレーターであることを思い出してください。





長所に加えて、コルーチンには欠点もあります。



  1. 戻り値を取得できません



    private IEnumerator LoadGoogle() { var www = new WWW("http://google.com"); yield return www; //  www.text    . }
          
          



  2. エラー処理



     private IEnumerator LoadGoogle() { try { var www = new WWW("http://google.com"); yield return www; } catch { yield return null; } }
          
          



  3. コールバック付き松葉杖



     private IEnumerator LoadGoogle(Action<string> callback) { var www = new WWW("http://google.com"); yield return www; if (callback != null) { callback(www.text); } }
          
          



  4. コルーチンで重いメソッドを処理しないでください



      void Start() { Debug.Log(string.Format("Thread id in start method = {0}", Thread.CurrentThread.ManagedThreadId)); StartCoroutine(this.HardMethod()); } private IEnumerator HardMethod() { while (true) { Thread.Sleep(1001); Debug.Log(string.Format("Thread id in HardMethod method = {0}", Thread.CurrentThread.ManagedThreadId)); yield return new WaitForEndOfFrame(); } } //Output: //Thread id in start method = 1 //Thread id in HardMethod method = 1 //Thread id in HardMethod method = 1 //Thread id in HardMethod method = 1
          
          





前述のように、コルーチンはメインスレッドで機能します。 このため、重いメソッドを起動してフリーズを取得します。



これらの欠点の多くは、リアクティブエクステンションの助けを借りて簡単に解消できます。リアクティブエクステンションは、将来、さらに多くの異なる機能をもたらし、開発を容易にします。



リアクティブ拡張とは何ですか?



リアクティブ拡張機能は、Linqスタイルのイベントと非同期呼び出しを操作できるライブラリのセットです。 このような拡張機能の目標は、非同期の相互作用が現れるコードの記述を単純化することです。 Unityは、基本的なリアクティブ拡張機能を提供するUniRxライブラリを使用します。 UniRx-.NET Reactive Extensionsに基づくUnityのリアクティブエクステンションの実装。 なぜこのネイティブ実装を使用できないのですか? Unityの標準RXが機能しないためです。 ライブラリはクロスプラットフォームであり、PC / Mac / Android / iOS / WP8 / WindowsStoreプラットフォームでサポートされています。



UniRxは何を提供しますか?



どのように機能しますか?



リアクティブエクステンションのコアは、 IObserver



および
IObservable



です。
それらは、オブザーバー設計パターンとしても知られるプッシュ通知の一般的なメカニズムを提供します。






All Articles