Frage an api, xna, c#, .net – Was ist der Vorteil von out / ref gegenüber return?

9

Ich mache ein Spiel mit dem XNA-Framework, daher verwende ich viele Funktionen, die Vektoren bearbeiten. (insbesondereVector2 (64bit struct)). Was mich stört, ist, dass die meisten Methoden mit ref- und out-Parametern definiert sind. Hier ist ein Beispiel:

<code>void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
</code>

das sieht mir auch ein bisschen komisch aus. Es gibt auch eine andereMin was offensichtlicher ist

<code>public static Vector2 Min(Vector2 value1, Vector2 value2);
</code>

Grundsätzlich haben fast alle Funktionen Überladungen mitrefs undouts. Ähnlich, andereAPIs.

Was ist der Vorteil dieses Designs? XNA ist auf Leistung optimiert, könnte es ein Ergebnis sein? Angenommen, Quaternion benötigt 128b, wenn weniger ref vorbeigeht.

BEARBEITEN:

Hier ist ein Testcode:

<code>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);
    }
}
</code>

Die Ergebnisse:

refOut1 2200refOut2 1400

Win 7 64bit, .Net 4. XNA 4.0

Auch IL-Code

<code>.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
</code>

und

<code>.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
</code>

Scheint, dass Overhead durch temporären Vector verursacht wird. Auch habe ich 1GHz WP 7.5 Gerät ausprobiert:

19791677

Anzahl der Ticks für eine um eine Größenordnung geringere Anzahl von Iterationen.

Ich denke dasecht Frage ist, "sollte .NET nicht RVO tun?" Mehrdad

Deine Antwort

2   die antwort
7

dh, wenn sie als Wert zurückgegeben wird, wird eine Kopie zurückgegeben, anstatt einen Verweis auf eine vorhandene Struktur zurückzugeben. Durch die Verwendung von ref / out-Parametern können Sie diese Kopie vermeiden, sodass der in der Min-Methode erstellte Vektor der exakte Vektor in Ihrem istresult Variable.

Dies ist eine der Mikrooptimierungen, von denen normalerweise abgeraten wird. In der Spielewelt wird dies jedoch häufig genug durchgeführt, und in Umgebungen, in denen die Leistung ausreicht, ist es die etwas weniger lesbare Option wert.

@PeterRitchie Vector2 ist eine veränderbare Struktur. Sie können einen neuen erstellen und ihm zuweisenresult (Eine triviale Operation für eine Struktur) und ändern Sie sie dann basierend auf der Logik in der Methode. Servy
Wenn Sie einem out / ref-Parameter einen Werttyp zuweisen, wird auch der Wert von der lokalen Variablen in den Parameter "kopiert". Peter Ritchie
@PeterRitchie Der ganze Punkt wäre, dass der out / ref-Parameter als lokale Variable in der gesamten Methode verwendet wird, sodass Sie nicht die Kopie von der lokalen Variablen zum out / ref-Parameter haben. Andernfalls, ja, würden Sie eine zusätzliche Kopie durchführen und dies würde den Zweck zunichte machen. Servy
Sie weisen einer Variablen weiterhin einen Wert zu (den Parameter). Die Zuweisung ist eine "Kopier" -Operation; Solange Sie einer Variablen (unabhängig vom Typ) einen Werttyp zuweisen, "kopieren" Sie den Wert. Peter Ritchie
Vielen Dank! Scheint, dass der Nutzen gerechtfertigt ist. 10% bis fast 50% der Beschleunigung. Lukasz Madon
3

ist die Möglichkeit, mehrere "Rückgabewerte" zu haben: Anstatt sie auf die übliche Weise zurückzugeben, listen Sie sie als ref / var-Parameter auf.

Das war mein erster Gedanke, aber sie geben nur 1 Wert zurück. Lukasz Madon
@ Lukas - in diesem Fall, ja, ich habe für den allgemeinen Fall geschrieben :) Attila

Verwandte Fragen