質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

2899閲覧

Unity、C#での非同期処理を2重に書く方法(非同期処理内に非同期処理を実現する)を教えてください

Oda_chin

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/05/16 09:59

編集2019/05/16 10:09

unityでゲームを作っています。C#の非同期処理の書き方について質問させていただきます。
下の該当コードがコンパイルエラーとなることは分かるのですが、非同期処理内に非同期処理を重ねて書く方法を知りたいです。

該当のソースコード(間違った文法です。実現したい内容として書いた例です)

C#

1private async void Update() 2{ 3 await StartCoroutine(Activate()); 4} 5 6private IEnumerator Activate() 7{ 8 if(flag==0){ 9 await StartCoroutine(A()); 10 } 11 else if(flag==1){ 12 await StartCoroutine(B()); 13 } 14 else if(flag==2){ 15 await StartCoroutine(C()); 16 } 17 yield return null; 18} 19 20private IEnumerator A() 21{ 22 処理a1; 23 await StartCoroutine(D()); 24 処理a2; 25 yeild return null; 26} 27 28private IEnumerator D() 29{ 30 処理d1; 31 yeild return null; 32 処理d2; 33} 34・・・

実装したいのは、上のコードを例とすると、
(B()やC()を書いていませんが、A()と同じ様な構造だとみなしてください)
1.
flagが0のとき
「処理a1、処理d1、処理d2、処理a2」
flagが1のとき
「処理b1、処理d1、処理d2、処理b2」
・・・
という順番で処理を行う。
(すなわち、await StartCoroutine(D());で終了待ちする。
すなわち、「処理a1、処理d1、処理a2、処理d2」などの順番にならない。)

flagが0や1など動的に変化するが、
「処理a1、処理d1、処理d2、処理a2」や「処理b1、処理d1、処理d2、処理b2」をそれぞれ1セットとみなし、
「処理a1、処理d1、処理b1、処理d2、処理a2」というふうに途中に別コルーチンの処理を挟まない。
(すなわち、await StartCoroutine(A());で終了待ちする。B()、C()も同じ。
すなわち、flagの変化に応じて「処理a1、処理d1、処理d2、処理a2」、「処理b1、処理d1、処理d2、処理b2」、「処理c1、処理d1、処理d2、処理c2」・・・と処理をする。)

というような、awaitによる終了待ちをA()とD()の2段階で行うプログラムです。
awaitが非同期メソッド(A()やB()、C())の中で記述できないために不便を強いられています。
回りくどい書き方(変数フラグを建てて管理する)をすると実装自体はできるのですが、分かりづらいコードになってしまうため、非同期処理内に非同期処理を書く方法をお尋ねしたい所存です。
ご教授よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まずUnityの場合、awaitやasyncは普通は使いません。
Unityの機能の大半はメインスレッドでしか使うことは出来ないので、「Unity外の機能をマルチスレッドで動作させたい」ということでなければ、awaitやasyncは使う機会はたぶん無いと思います。
しかし、それだと不便なので、その代わりとして存在するのがコルーチンです。
ただ、コルーチンの場合は、基本的にマルチスレッドで動作しているわけではないので、他の処理を動作させるためにyield return ~;で抜ける必要があります。
(そうしないと、フリーズの原因になります)

本題の、非同期処理内に非同期処理を書く方法ですが、以下のようにすれば、コルーチンの中でコルーチンを実行することができます。

C#

1private IEnumerator Activate() 2{ 3 if(flag==0){ 4 yield return A(); 5 } 6 else if(flag==1){ 7 yield return B(); 8 } 9 else if(flag==2){ 10 yield return C(); 11 } 12} 13 14private IEnumerator A() 15{ 16 処理a1; 17 yield return D(); 18 処理a2; 19} 20 21private IEnumerator D() 22{ 23 処理d1; 24 yield return null; 25 処理d2; 26}

これで「1.」は解決できると思います。

「2.」に関してですが、「他の処理に渡さずに待機させる」ことは出来ませんので、以下のように「実行中は別のコルーチンを開始させない」ようにするしかないと思います。

C#

1bool isRunCoroutine = false; 2 3private void Update() 4{ 5 if (!isRunCoroutine){ 6 isRunCoroutine = true; 7 StartCoroutine(Activate()); 8 } 9} 10 11private IEnumerator Activate() 12{ 13 if(flag==0){ 14 yield return A(); 15 } 16 else if(flag==1){ 17 yield return B(); 18 } 19 else if(flag==2){ 20 yield return C(); 21 } 22 isRunCoroutine = false; 23}

(そもそも、Update()は毎フレーム呼ばれる関数で、終了させないと次のフレームの処理が出来ないので、awaitのような処理で待機させてはいけないです)

投稿2019/05/16 11:44

fiveHundred

総合スコア9797

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Oda_chin

2019/05/16 12:25

非同期処理について調べているうちにawaitの書き方へ行きつき、混濁していました。根本的な事柄についてお教えいただきありがとうございます。 また、2.について、やはり変数で管理するのが一般的なのですね。Activate()に相当するコルーチンが複数になると、処理の時系列的な管理が大変になると思い、非同期処理内で非同期処理を行う方法について質問させていただきました。 参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問