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

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

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

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

Unity

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

Q&A

解決済

1回答

1445閲覧

UniTaskでStart関数で非同期処理を待機し,完了するまでUpdate関数の実行を待機する

leaf21341

総合スコア10

C#

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

Unity

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

0グッド

0クリップ

投稿2023/09/27 08:34

実現したいこと

UniTaskでStart関数で非同期処理を待機し,完了するまでUpdate関数の実行を待機する

発生している問題

下記該当のソースコードのように,UniTaskでStart関数内でawaitをするとStart関数が完了する前にUpdateが実行されてしまいます.
期待する動作としては,Start関数で5秒待機した後にUpdateが実行して欲しいのですが...
直感的にはうまくいきそうなのですが,なぜ期待通りに動作しないのでしょうか?
ご回答よろしくお願いいたします.

該当のソースコード

Update関数が直ちに呼ばれてしまう例

C#

1public class Test : MonoBehaviour 2{ 3 async void Start() 4 { 5 await UniTask.Delay(5000); 6 } 7 void Update() 8 { 9 Debug.Log("start update"); 10 } 11}

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

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

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

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

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

guest

回答1

0

ベストアンサー

Update()はあくまで毎フレーム実行する関数です。
Start()が終わって無かろうが、全く関係ありません。

awaitは単純に「待機する」ではなく、「処理を途中で中断して、他の処理を行った後に再開する」と考えたほうが分かりやすいかもしれません。

以下のようにすればいいです。

C#

1public class Test : MonoBehaviour 2{ 3 bool isFinishStartFunc = false; // Start()が終わったかどうか 4 5 async void Start() 6 { 7 await UniTask.Delay(5000); 8 9 isFinishStartFunc = true; 10 } 11 void Update() 12 { 13 if (!isFinishStartFunc) 14 { 15 // Start()が終わっていなければ何もしない 16 return; 17 } 18 19 Debug.Log("start update"); 20 } 21}

投稿2023/09/27 08:52

編集2023/09/27 08:55
fiveHundred

総合スコア10277

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

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

leaf21341

2023/09/27 09:12

回答ありがとうございます. > Update()はあくまで毎フレーム実行する関数です。 > Start()が終わって無かろうが、全く関係ありません。 こちらについてですが,例えばStart関数で非常に重い同期処理があった場合も,Update関数がよばれてしまうのでしょうか? Unityのライフサイクルでは「最初のフレームのアップデート前に Start が呼び出されます。」とのことでしたので少し混乱しています.
fiveHundred

2023/09/27 09:28

> こちらについてですが,例えばStart関数で非常に重い同期処理があった場合も,Update関数がよばれてしまうのでしょうか? はい。そうです。 > Unityのライフサイクルでは「最初のフレームのアップデート前に Start が呼び出されます。」とのことでしたので少し混乱しています. これはStart()が呼ばれるだけで、それが終了したかどうかは関係ありません。 今回の場合、以下のような処理になります。 1. Start()が呼ばれる 2. 「await UniTask.Delay(5000);」で処理が中断される 3. その間にUpdate()が呼ばれる(5秒経過するまで、呼ばれ続ける) 4. 5秒経過したら、Start()の続きが行われる これはUniTaskではなくコルーチンでも同じです。
tamoto

2023/09/28 02:08

> Start関数で非常に重い同期処理があった場合 これは本当に「同期処理」であるなら、Update に使うスレッドを Start が長時間専有する形になるので、Update の実行が Start の完了後まで遅れる挙動になるのではないでしょうか。 > Unityのライフサイクルでは…… これは Start が通常の同期メソッドである場合の話で、そもそも非同期メソッドにするというのは「メソッドの実行コンテキストを Unity のライフサイクルから外す」という指示なので、Start の実行状況に関係なく Update の回転が始まるのは、あなたがそう指示したからです。
fiveHundred

2023/09/28 02:46

> これは本当に「同期処理」であるなら、Update に使うスレッドを Start が長時間専有する形になるので、Update の実行が Start の完了後まで遅れる挙動になるのではないでしょうか。 すみません、「同期処理」という単語を見落としていました。 私が言ったのは、非同期処理についてです。 「同期処理」の場合、確かにStart()は長時間専有する形になります。 そうなってしまうと、その間はUpdate()どころか、他の処理も行われなくなるので、やってはいけないことの1つです。 言い訳ですが、その前提があったので、「同期処理」であることを、そもそも初めから考えていませんでした。 > これは Start が通常の同期メソッドである場合の話で、そもそも非同期メソッドにするというのは「メソッドの実行コンテキストを Unity のライフサイクルから外す」という指示なので、Start の実行状況に関係なく Update の回転が始まるのは、あなたがそう指示したからです。 UniTaskの場合、コルーチンのように「1フレーム分待機する」などの処理も行えます。 この場合だと、「Unity のライフサイクルから外す」とは言い切れないような気もしますが、どうなのでしょうか? (それとも、全く別の理由で「Unity のライフサイクルから外す」という言葉を使ったのでしょうか?)
UnitySoldier

2023/09/28 04:24 編集

> Unityのライフサイクルでは…… これは Start が通常の同期メソッドである場合の話で、そもそも非同期メソッドにするというのは「メソッドの実行コンテキストを Unity のライフサイクルから外す」という指示なので、Start の実行状況に関係なく Update の回転が始まるのは、あなたがそう指示したからです。 UniTaskは内部的にPlayerLoopで駆動するからライフサイクルから外れないと思うんですよねえ https://neue.cc/2021/02/26_599.html >>UniTaskも基本的にはPlayerLoop上で動かしているのですが、自由に任意の実行箇所を選べるように、28個のループを挿入しています 補足:UniTask.RunOnThreadPoolとか明示的にやれば完全にライフサイクルから外すことはできますし完全なPlayerLoop依存ではない 補足2: どのPlayerLoopを選ぶかも実はカスタムできる https://github.com/Cysharp/UniTask#playerloop 補足3: Await自体はネイティブのタイミングでのチェックなので確かに完全なライフサイクルとの結合ではない。 それに同じ処理をStartCorutineとか完全なGameObject駆動で実行される同じ内容の非同期処理を書いたとしても同じような結果になるので ライフサイクル云々は関係なく、Update()とStart()はMonoBehaviorに実装されてるコールバックみたいなものなので独立して発火するからそれぞれの内部で非同期処理を入れても関係なく機能するってだけの話ですよね。  というかUnityの非同期処理は伝統的にPlayerLoop依存の方が多い気がする....TaskとかWebGLでちゃんと動かないし...
tamoto

2023/09/28 04:35

> ……、どうなのでしょうか? 失礼しました、「ライフサイクル」と言ったのは、「オブジェクトの処理が Awake->Start->(Update->Update->...)-> の順序で動く」という最初の取り決めのことを指したつもりでいて、Start やその他の関数を非同期にした場合にこれが成り立たなくなることを表現したつもりでした。 コルーチンや UniTask 含め、非同期はこのメインのフローから外れたコンテキストで動作することを言いたかったのです。
leaf21341

2023/09/28 08:58

①Unityのライフサイクル.... UniTaskはPlayerLoop上で動作しているのでライフサイクルからは外れない ②Start関数で非常に重い同期処理があった場合... (メインスレッドを長時間占有するが)ライフサイクル通り順次実行される ③UniTaskでStart関数内でawaitをするとStart関数が完了する前にUpdateが実行されてしまいます. (非同期なStart関数はPlayerLoopによってfire-and-forgetで実行されるので)awaitしてもStart関数自体の完了をメインスレッドが待機するわけではない. 御三方の意見と,他記事を参照して以上のように理解しました. 何かおかしな点があればご指摘をいただけるとたすかります.
leaf21341

2023/09/28 09:01

また,そもそもの表題についてですが 「Start関数で非同期処理をawaitし,完了するまでUpdate関数の実行を待機する方法はフラグ管理以外ではない」 というふうになると理解しました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問