イベントシステムを設定するより良い方法はありますか?


9

イベントシステムは驚くべきものであり、非常に扱いにくいコードを飼いならし、オブジェクトとゲームループの簡単な通信を通じてゲームの動的な作成を可能にします。現在の実装の効率に苦労しています。現在、オブジェクトのリストをそれらが応答するイベントに分離するという私のわずかな最適化は不思議に思っていますが、私ができることがもっとあるはずです。

現在、私は2つの方法があります:

  1. 最も単純:イベントが送信されると、すべてのオブジェクトがベクターに追加されますすべてのオブジェクトには、handle_event()メソッドを介してイベントが送信されます。

  2. より複雑:キーが文字列、値が整数のマップがあります。イベントタイプが追加されると、それはこのマップに追加され、intは単純にインクリメントされます(より良い方法が必要
    です)。次に、オブジェクトのベクトルのベクトルが新しいベクトルを押し戻し、そのタイプのイベントを処理します。
    イベントが呼び出されると、eventTypesマップの対応するintをオブジェクトのベクターのベクター内の型に呼び出し、そのイベントタイプを処理する各オブジェクトにそのイベントを送信します。

これらの最初の方法は、多くのオブジェクトに対して(明らかに)非常に低速ですが、非常に少数のオブジェクトに対しては非常に高速です。2番目の方法は、異なるタイプのイベントを処理したい大きなオブジェクトでは非常に高速ですが、同じタイプのイベントを処理するオブジェクトを使用するオブジェクトごとの最初の方法よりも低速です。

より速い(実行時間に関して)方法はありますか?文字列型からintを検索するより速い方法はありますか?(最初は列挙型がありましたが、必要なレベルのダイナミズムのために必要なカスタム型は許可されていませんでした。)


1
これは、ハッシュマップ(またはハッシュテーブル)の目的の一種であり、文字列はハッシュ番号に計算され、配列で直接検索するために使用されます。en.wikipedia.org/wiki/Hash_table
Patrick Hughes、

良い質問は、これは本当にパフォーマンスのボトルネックなのか、それとも時期尚早に心配しているのか、です。
Jari Komppa、2011

これはすでに実装されており、多くのオブジェクトが使用されるとボトルネックが発生します。ボトルネックの欠如に関する私の以前のコメントはアプリケーション自体ではなく、実際には同じ数のオブジェクトが実際に処理された上記の2つの実装間の速度の違いでした。イベントシステムを作成する他の方法を期待していました...しかし、このスレッドのアイデアの一部は、特にイベントシステムのロード(100000オブジェクトで11-25フル秒のロード時間)で速度をかなり向上させます
ultifinitus

10万個のオブジェクトは、ゲームだけではひどく高く聞こえます。これはサーバーですか、それともエンドユーザークライアントアプリケーションですか?
Patrick Hughes

これは私のエンジンなので、私は本当に柔軟性を求めています。サーバーアプリケーションおよびエンドユーザーアプリケーションで使用されます(あまり多くはないが最初の最適化)
ultifinitus

回答:


5

パフォーマンスのボトルネックが文字列名からイベントID(整数)を検索していると言っているようです。ゲームを実行する前に、またはレベルのロード中に、ゲームデータを前処理してすべてのイベント名を整数に変換できます。その後、ゲームプレイ中に変換を行う必要はありません。

オブジェクトが頻繁に作成および破棄されている場合、オブジェクトのベクトルに大量のチャーンが発生する可能性があります。この場合、ベクターの代わりにリンクリストを使用するとメリットがあります。挿入と削除が高速です。


ボトルネックは大きくありません(100,000オブジェクトの場合、オブジェクトごとに.0000076 msを失います)が、あなたのアイデアは素晴らしいアイデアだと思います。実際にはIDの1回限りのルックアップを実行し、eventIDを元の文字列データではなくintとして格納することになると思います。そして、私は実際にはリンクされたリストについては考えていませんでした。
ultifinitus 2011

1
+1 IDの前処理用。また、各モジュールがのようなものを介して取得できるEventTypeタイプを用意することで、それを遅延して行うこともできますEventType takeDamageEvent = EventSystem::CacheEventType("takeDamageEvent");。それをクラスの静的メンバーにすると、それを必要とする各クラスに1つのコピーしか浮かびません。
michael.bartnett 2011

2
文字列の代わりにIDを保存すると、デバッグが多少難しくなることに注意してください。オブジェクトがどこから来たのかを指定するテキストを見ることができると、いつでも役に立ちます。idと文字列の両方を保存することにより、途中まで進むことができます。これらは、デバッグ目的で保持します(おそらく、リリースビルドでは削除されています)。
Nicol Bolas、2011

2

さて、最初に簡単なものを邪魔にならないようにしましょう。これはmap、文字列(おそらくイベントの名前)と整数(登録されたイベントリスナーのインデックス)の間にあります。

のルックアップ時間はmap、マップ内のアイテムの数と、2つのキーの比較にかかる時間(キャッシュの問題を無視)の2つに基づいています。ルックアップ時間に問題がある場合、それを処理する1つの方法は、文字列タイプを変更して比較関数を変更することです。

std::stringoperator<比較のために使用していると仮定しましょう。これは非常に非効率的です。バイト単位の比較を行います。実際の「より小」の比較は気にしません。厳密に弱い順序付けを行うある種の比較が必要なだけです(map他の方法では機能しないため)。

したがって、の代わりに32バイトの固定長文字列を使用する必要がありますstd::string。これらを識別子に使用します。これらの固定文字列の比較テストでは、バイト単位の比較は行われません。代わりに、32ビット(または64ビット)の比較を行います。符号なし整数として4バイトごとに取得し、それを他の文字列の対応する4バイトと比較します。このようにして、比較は最大で8つの比較のみを受け取ります。順序は文字としてのデータとは関係ありませんが、厳密に弱い順序を保証します。

31バイトより長い文字列(NULL文字が必要)を格納すると、文字列が切り捨てられます(ただし、末尾ではなく中央から切り捨てられます。エントロピーは最初と最後で最大になる傾向があることがわかります)。そして、それより短い文字列は、残りの文字をで埋め\0ます。

これで、map全体を破棄してハッシュテーブルを使用できます。実際に100,000を超える種類のイベントタイプがある場合、これは良い考えです。しかし、それがリモートで合理的なものになるゲームについては知りません。


したがって、std :: stringの代わりに32バイトの固定長文字列を使用する必要があります。素晴らしい!文字列のタイプを変更することは考えていませんでした。
ultifinitus 2011

0

一般的な質問に答えるには:

イベントシステムを設定するより良い方法

なにもない。できることは、イベントシステムに必要な特定のニーズを特定し(いくつか異なる場合があります)、適切なジョブに適切なツールを使用することです。

私は大量のイベントシステムを実装して一般化しようとしましたが、この結論に達しました。オブジェクト階層または黒板などを使用する場合、コンパイル時または実行時にする場合、tradoffは実際には異なります。

最善の方法は、さまざまな種類のイベントシステムを調査することです。そうすると、どの場合にどのイベントシステムを使用するかについての手掛かりが得られます。

ここで、本当に最も柔軟なシステムが必要な場合は、イベントの動的プロパティを備えた黒板システム(実行時)を実装すると、非常に柔軟ですが、おそらく非常に遅くなります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.