web-dev-qa-db-ja.com

長時間実行オペレーションを段階的なオペレーションに変換しますか?

Unityでビデオゲームに取り組んでおり、ある時点で解決するのが難しい問題に直面しています。

レベルデータの読み込み中にゲームがフリーズします。

数秒かかるプロセスで何が起こっているのかを説明しましょう:

  • セクション、面、頂点で構成されるトラックメッシュデータをロードする
  • トラックテクスチャをロードし、それらからメッシュのアトラスを構築する
  • 前述のデータを使用してトラックメッシュを作成する

この読み込みプロセスには数秒かかります。大きさの大きい風景を読み込む必要があるため(まだ完了していないため)、さらに長くなることが予想されます。

考慮事項:

このロードプロセスの一部のステップは、Unityからオブジェクトをインスタンス化するため、バックグラウンドスレッドでは実行できません。これは、メインスレッドからのみ実行できます。テクスチャ、メッシュなどを作成します。

問題を解決するための試みとアイデア:

  • start coroutine 、これは、単一のフレーム内で実行されることが期待されているため、単に機能しません。ロードプロセスには数百のフレームがかかり、フレームは1/60秒です

  • ロードをチャンクに分割し、フレームごとにそれぞれを処理します。解決策になる可能性がありますがトリッキーです

    • 必要に応じて、ディスパッチャを使用してエンジンオブジェクトを生成します。つまり、適切なスレッドで実行される非同期呼び出しを使用します。生のピクセルから最終的なテクスチャを作成する

2番目のアプローチは正しいと思われるので、これに焦点を当てますが、別のアプローチを受け入れることもできます。

質問:

長時間実行オペレーションを小さなオペレーションに分割するために使用できるアプローチまたはパターンは何ですか?

(それが十分に明確であることを願っています。それ以外の場合はお知らせください。)

編集:コメントの後の説明:

基本的に私の問題は単純ですが、修正が困難です。UIがフリーズするので、問題が発生するのは、アクセスが必要なためにタスクが通常よりも長くかかるためです。全体を書き直さずにこれをリファクタリングする方法については複雑です。私はこれに取り組むためのより簡単で同等に効果的なアプローチがあると信じています。

これから他の2つのアイデアが浮かび上がります。

  • Dispatcherアプローチ。すべてをバックグラウンドスレッドで実行し、必要に応じてエンジン呼び出しをラップします。UIは少しだけフリーズします。 AAAゲームでも発生するので問題ありません

  • 静的読み込み画面、問題を知覚的に隠しますが、まったく解決しません

3
Aybe

ハード制約

データをMeshに割り当てる必要があります。それが起こる必要があります。
それを回避する方法はありません。

Unity APIはスレッドセーフではないため、メインスレッドでmustする必要があります。
それを回避する方法はありません。

したがって、ここですでに確立できるのは、assigningメッシュへのデータのいずれかが(あまりにも)長くかかる場合、これはできると思いますt変更される;時間がかかります。ただし、ここではおそらくデータの読み取りと読み込みが行われ、処理時間が非常に長くなります。

コルーチン

「コルーチンを開始する」と「ローディングをチャンクに分割する」という2つのアイデアは、実際には同じです。これは、パフォーマンス管理の観点からコルーチンで実行できることは、「OK、このフレームにはこれで十分です。次のフレームで続けましょう」と言うことです。

public IEnumerator ExecuteSomethingThatTakesLong()
    {
        for (int i = 0; i < 200; i++)
        {
            // A function that takes time to execute. Doing this 200 times
            // in a row takes about a second, causing a lag.
            TakeTime(10000);

            // By waiting after each step, it will definitely take 200 frames
            // to complete, but no noticable lag occurs.
            yield return null; 
        }
    }

したがって、コルーチンから必要なものを取得するには、とにかく「ロードをチャンクに分割する」必要があります。その問題は、チャンクの適切なサイズを見つける必要があることです。適切に機能するチャンクサイズを見つけた場合、パフォーマンスの低いマシンでは大きすぎる可能性があります。すべての単一フレームがliiittleビットが多すぎます。

もちろん、それは解決できない問題ではありません。十分なマージンなどを残すだけで十分です。ただし、3Dモデルファイルの分割には独自の課題がないわけではなく、さらに複雑になります。

あなたが例えばWebGLプラットフォーム用にビルドする必要があり、スレッドをhaveしないでください。これがこの問題を攻撃する唯一の角度です。ただし、あなたの質問から、スレッドを許可するプラットフォーム(=他のほとんどすべてのプラットフォーム)で作業しているようです。

ここで何ができるか

スレッドを使用できる場合は、ここで簡単に選択できます。彼らが言うには

問題があります。スレッドで解決します。 2つの問題があります。

そして、私は同意しますが、この場合、スレッドは本当に簡単な代替手段のようです。

幸運なことに(またはおそらく誰かがこれについて考えたため)Meshは本当にプリミティブなデータで動作します。ここではVector3sとint[]sについて話しています。 Vector3はUnity APIの一部ですが、スレッドセーフであるという点で例外です。

これから最大のパフォーマンスの向上を引き出すために、私は Mesh のデータをミラーリングするクラスを作成することをお勧めします。さて、あなたが少なくとも必要な部品。そうすれば、別のスレッドで必要なすべてのデータを入力できるクラスができます。その後、完了したら、メインスレッドですべてのプロパティを1つずつコピーします。

本当に必要な場合は、またコルーチンを使用してデータを分割してさらに割り当てることができます(最初に頂点を割り当て、次のフレームに三角形、次のフレームはUV ...)。

1
R. Schmitz