2012-05-10 10 views
9

私はXNAフレームワークを使ってゲームを作っているので、ベクトルで動作する多くの関数を使用します。 (特にVector2(64ビット構造体))。私にとって気になるのは、ほとんどのメソッドがrefとoutパラメータで定義されているということです。ここに例があります:out/refとreturnを使用するメリットは何ですか?

void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result) 

少し奇妙に見えます。また

public static Vector2 Min(Vector2 value1, Vector2 value2); 

は、基本的には、ほぼすべての機能がref sおよびout sのオーバーロードがあり、より明白である別のMinがあります。同様に、他APIs

このデザインの利点は何ですか? XNAはパフォーマンスに最適化されています。 Quaternionは128bを必要とします。

EDIT:

  • refOut1 2200
  • refOut2 1400

勝利7 64:

public class Game1 : Microsoft.Xna.Framework.Game 
{ 
    GraphicsDeviceManager graphics; 
    SpriteBatch spriteBatch; 

    private Vector2 vec1 = new Vector2(1, 2); 
    private Vector2 vec2 = new Vector2(2, 3); 
    private Vector2 min; 
    private string timeRefOut1; 
    private string timeRefOut2; 
    private SpriteFont font; 

    public Game1() 
    { 
     graphics = new GraphicsDeviceManager(this); 
     Content.RootDirectory = "Content"; 

     refOut1(); 
     refOut2(); 
    } 

    private Vector2 refOut1() 
    { 
     Vector2 min = Vector2.Min(vec1, vec2); 
     return min; 
    } 

    private Vector2 refOut2() 
    { 
     Vector2.Min(ref vec1, ref vec2, out min); 
     return min; 
    } 

    protected override void Initialize() 
    { 
     const int len = 100000000; 
     Stopwatch stopWatch = new Stopwatch(); 
     stopWatch.Start(); 
     for (int i = 0; i < len; i++) 
     { 
      refOut1(); 
     } 
     stopWatch.Stop(); 

     timeRefOut1 = stopWatch.ElapsedMilliseconds.ToString(); 

     stopWatch.Reset(); 
     stopWatch.Start(); 
     for (int i = 0; i < len; i++) 
     { 
      refOut2(); 
     } 
     stopWatch.Stop(); 

     timeRefOut2 = stopWatch.ElapsedMilliseconds.ToString(); 

     base.Initialize(); 
    } 

    protected override void LoadContent() 
    { 
     spriteBatch = new SpriteBatch(GraphicsDevice); 
     font = Content.Load<SpriteFont>("SpriteFont1"); 
    } 

    protected override void Update(GameTime gameTime) 
    { 
     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 
      this.Exit(); 

     base.Update(gameTime); 
    } 

    protected override void Draw(GameTime gameTime) 
    { 
     GraphicsDevice.Clear(Color.CornflowerBlue); 

     spriteBatch.Begin(); 
     spriteBatch.DrawString(font, timeRefOut1, new Vector2(200, 200), Color.White); 
     spriteBatch.DrawString(font, timeRefOut2, new Vector2(200, 300), Color.White); 
     spriteBatch.End(); 

     // TODO: Add your drawing code here 

     base.Draw(gameTime); 
    } 
} 

結果:

ここでは、テストコードです。ネット4. XNA 4.0

またILコード

.method public hidebysig static void Min(valuetype Microsoft.Xna.Framework.Vector2& value1, 
              valuetype Microsoft.Xna.Framework.Vector2& value2, 
              [out] valuetype Microsoft.Xna.Framework.Vector2& result) cil managed 
{ 
    // Code size  69 (0x45) 
    .maxstack 3 
    IL_0000: ldarg.2 
    IL_0001: ldarg.0 
    IL_0002: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0007: ldarg.1 
    IL_0008: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_000d: blt.s  IL_0017 
    IL_000f: ldarg.1 
    IL_0010: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0015: br.s  IL_001d 
    IL_0017: ldarg.0 
    IL_0018: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_001d: stfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0022: ldarg.2 
    IL_0023: ldarg.0 
    IL_0024: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0029: ldarg.1 
    IL_002a: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_002f: blt.s  IL_0039 
    IL_0031: ldarg.1 
    IL_0032: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0037: br.s  IL_003f 
    IL_0039: ldarg.0 
    IL_003a: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_003f: stfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0044: ret 
} // end of method Vector2::Min 

.method public hidebysig static valuetype Microsoft.Xna.Framework.Vector2 
     Min(valuetype Microsoft.Xna.Framework.Vector2 value1, 
      valuetype Microsoft.Xna.Framework.Vector2 value2) cil managed 
{ 
    // Code size  80 (0x50) 
    .maxstack 3 
    .locals init (valuetype Microsoft.Xna.Framework.Vector2 V_0) 
    IL_0000: ldloca.s V_0 
    IL_0002: ldarga.s value1 
    IL_0004: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0009: ldarga.s value2 
    IL_000b: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0010: blt.s  IL_001b 
    IL_0012: ldarga.s value2 
    IL_0014: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0019: br.s  IL_0022 
    IL_001b: ldarga.s value1 
    IL_001d: ldfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0022: stfld  float32 Microsoft.Xna.Framework.Vector2::X 
    IL_0027: ldloca.s V_0 
    IL_0029: ldarga.s value1 
    IL_002b: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0030: ldarga.s value2 
    IL_0032: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0037: blt.s  IL_0042 
    IL_0039: ldarga.s value2 
    IL_003b: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0040: br.s  IL_0049 
    IL_0042: ldarga.s value1 
    IL_0044: ldfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_0049: stfld  float32 Microsoft.Xna.Framework.Vector2::Y 
    IL_004e: ldloc.0 
    IL_004f: ret 
} // end of method Vector2::Min 

オーバーヘッドが一時ベクターによって引き起こされると思われます。反復の大きさより小さな数の順序のためにダニの

番号:また、私は1GHzのWP 7.5デバイスを試みました。

+1

私は本当の質問は ".NETはRVOを実行すべきではないのですか?"と思います。 – Mehrdad

答えて

7

Vector2は構造体です。つまり、Vector2は値として返されると、既存の構造体への参照を返すのではなく、コピーが返されます。 ref/outパラメータを使用することで、このコピーを避けて、Minメソッドで作成したVectorがresult変数の正確なベクトルになるようにすることができます。

これは、通常は落胆するマイクロ最適化の1つですが、ゲームの世界では頻繁に行われます。パフォーマンスが十分に重要な環境では、読みにくいオプションのほうが価値があると考えられます。

+0

out/refパラメータに値タイプを割り当てることは、ローカル変数からその値をパラメータに「コピー」しています。 –

+2

@PeterRitchieローカル変数からout/refパラメータへのコピーを持たないように、out/refパラメータがメソッド全体でローカル変数として使用されることが、全体のポイントになります。それ以外の場合は、追加コピーを実行して目的を破ることになります。 – Servy

+1

変数の値を別の変数(パラメータ)に割り当てています。割り当ては「コピー」操作です。型に関係なく値の型を変数に代入している限り、値を "コピー"しています。 –

3

Servyで言及されているパフォーマンス効率のもう1つの違いは、複数の「戻り値」を持つことです。通常の方法で戻す代わりに、それらをref/varパラメータとしてリストします。

+2

それは私の最初の考えですが、彼らは1つの値を返すだけです。 –

+0

@lukas - この場合、はい、私は一般的なケースのために書いていました:) – Attila

関連する問題