Unityがパフォーマンスについて話しているときに、for each
パフォーマンスを向上させるためにループを回避し、代わりに通常のforループを使用するように指示されました。実装の観点for
との違いは何for each
ですか?for each
非効率なものは何ですか?
Unityがパフォーマンスについて話しているときに、for each
パフォーマンスを向上させるためにループを回避し、代わりに通常のforループを使用するように指示されました。実装の観点for
との違いは何for each
ですか?for each
非効率なものは何ですか?
回答:
foreachループは、見かけ上、渡したコレクションからIEnumeratorオブジェクトを作成し、その上を移動します。したがって、次のようなループ:
foreach(var entry in collection)
{
entry.doThing();
}
これは、次のようなものに変換されます
(列挙子が後で破棄される方法に関する複雑さを排除します)。
var enumerator = collection.GetEnumerator();
while(enumerator.MoveNext()) {
var entry = enumerator.Current;
entry.doThing();
}
これが単純または直接コンパイルされた場合、その列挙型オブジェクトはヒープに割り当てられます(少し時間がかかります)。その基礎となる型が構造体(ボクシングと呼ばれるもの)であってもです。ループが完了すると、この割り当ては後でクリーンアップするためのガベージになり、コレクターがフルスイープを実行するのに十分なガベージが山積みになると、ゲームが一瞬途切れることがあります。最後に、コンパイラがそのアクションをインライン化しない場合、MoveNext
メソッドとCurrent
プロパティは、で直接項目を取得するよりも多くの関数呼び出しステップを含む可能性がありますcollection[i]
。
上記のUnityドキュメントのHelliumリンクは、ネイティブアレイ以外のものを反復処理した場合、この単純な形式がバージョン5.5より前の Unityで発生するものとまったく同じであることを示しています。
バージョン5.6以降(2017バージョンを含む)では、この不要なボクシングはなくなりました。具体的なタイプ(例:int[]
またはList<GameObject>
またはQueue<T>
)を使用している場合、不要な割り当ては発生しません。
問題のメソッドが、ある種のIListまたは他のインターフェイスで動作していることだけを知っている場合でも、割り当てを取得できます。これらの場合、動作している特定の列挙子がわからないため、最初にIEnumeratorオブジェクトにボックス化する必要があります。 。
したがって、これは、現在のUnity開発ではそれほど重要ではない古いアドバイスである可能性が高いです。私たちは物事についてのビット迷信ことができるようにUnityは、開発者に使用ので、塩の粒とそのフォームのいずれかのアドバイスを取り、古いバージョンでは遅い/の毛深いします。;)エンジンは私たちが信じているよりも速く進化します。
実際には、ゲームでforeachループを使用することによる顕著な遅延やガベージコレクションの問題が発生することはありませんが、実際の距離はさまざまです。選択したハードウェアでゲームのプロファイルを作成して、心配する価値があるかどうかを確認します。必要に応じて、問題が発生した場合に、開発の後半でforeachループを明示的なforループに置き換えることは非常に簡単です。そのため、開発の早い段階で読みやすさとコーディングの容易さを犠牲にしません。
List<MyCustomType>
およびa IEnumerator<MyCustomType> getListEnumerator() { }
は問題ありIEnumerator getListEnumerator() { }
ませんが、メソッドはそうではありません。
オブジェクトのコレクションまたは配列(プリミティブデータ型以外のすべての要素の配列)にfor eachループが使用されている場合、GC(ガベージコレクター)が呼び出され、for eachループの最後で参照変数のスペースが解放されます。
foreach (Gameobject temp in Collection)
{
//Code Do Task
}
一方、forループはインデックスを使用して要素を反復処理するために使用されるため、プリミティブデータ型は非プリミティブデータ型と比較してパフォーマンスに影響を与えません。
for (int i = 0; i < Collection.length; i++){
//Get reference using index i;
//Code Do Task
}
temp
ここで、変数はそう、(それはすでにヒープ上の既存のエントリへの参照のみなので、その参照型のインスタンスを保持するために、新しいヒープメモリを割り当てていない)コレクションが参照型の完全である場合でも、スタックに割り当てることができますここでゴミが発生するとは思わないでしょう。列挙子自体は、状況によってはボックス化されてヒープになる可能性がありますが、それらのケースはプリミティブデータ型にも適用されます。