Jaka jest korzyść z używania out / ref versus return?
Tworzę gry z wykorzystaniem struktury XNA, więc używam wielu funkcji, które działają na wektorach. (w szczególnościVector2 (Struktura 64-bitowa)). Martwi mnie to, że większość metod jest definiowana z parametrami ref i out. Oto przykład:
void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
co też wydaje mi się trochę dziwne. Jest też innyMin
co jest bardziej oczywiste
public static Vector2 Min(Vector2 value1, Vector2 value2);
Zasadniczo prawie wszystkie funkcje mają przeciążeniaref
s iout
s. Podobne, innePszczoła.
Jakie są zalety tego projektu? XNA jest zoptymalizowany pod kątem wydajności, czy to może wynik? Powiedzmy, że kwaternion wymaga 128b, gdzie przechodzi przez ref mniej.
EDYTOWAĆ:
Oto kod testowy:
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);
}
}
Wyniki:
refOut1 2200refOut2 1400Win 7 64bit, .Net 4. XNA 4.0
Również kod 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
i
.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
Wydaje się, że narzut jest spowodowany przez temp Vector. Spróbowałem również urządzenia 1 GHz WP 7.5:
19791677Liczba znaczników dla rzędu wielkości mniejszej liczby iteracji.