■お詫びと訂正■
vectorをoperator[]でアクセスし、flag参照関数をinline化し、最適化かけたら同じ速度になりました。。。
汎用的・拡張性の高い(便利な)設計は、実行効率や速度が低下しがちです。
しかし、リソースが豊富な現在、実行効率を少々犠牲にしても、便利な設計を重視する方が良いという考え方もあります。
そこで、便利な設計⇔実行効率のトレードオフをどの辺で判断すべきか、検証してみました。
弾幕ゲー制作の中で一番肝になるのが、「弾」データの持ち方。
弾データは弾クラスの一つのオブジェクトですが、持ち方は以下の4通り位あるでしょう。
遅
↑
・メモリプールから確保できる形でlistを使う(new,deleteを繰り返す弾オブジェクトのリスト)
・タスクリストを使う
・vectorを使う
・配列を使う
↓
速
実行速度は上ほど遅い、下ほど早いと思われます。(vectorは安全に.at(i)でアクセス)
まずは、配列とvectorでどれ位変わるか調べてみました。
約5万個の弾を出した時の計算時間
[vector編]
計算部 = 915[ms]
描画部 = 27[ms]
[配列編]
計算部 = 267[ms]
描画部 = 16[ms]
なんと!vectorは配列の約3.5倍!
かなり処理に時間がかかるようです。
あらゆるアクセスに関数コールが生じるのがボトルネックのようです。(特にat?)
そこで、関数コールをなるべくしないように考えます。
弾クラスにはその弾が使用中かどうかを表すフラグ変数がありますが、この変数はprivateなので
bool IsUsing();
みたいな関数を通じてしか使用中かどうかチェック出来ません。
しかし、膨大な回数のこの関数コールが生じています。そこで、フラグ変数をpublicにし、直接参照するようにし、配列版をさらに高速に計算出来るように試みました。
すると・・・
[配列+関数コール削減版]
計算部 = 49ms
描画部 = 16ms
計算時間が約1/18になったではないですか!
どうも関数コールは相当なボトルネックになるようです。
とは言え、汎用性や拡張性を意識すると、どうしても関数に細分化しがちです。
この辺のトレードオフは基準が難しそうですが、頻繁にコールする関数はなるべく作らないように設計するのが良いようです。
(ちなみに上記関数はinlineにしても変化ありませんでした。使い方が悪いのかな・・)
※追記:最適化かかってないだけでした;
もっとこうすればいいとかあれば、何かご意見もらえると嬉しいです!