gpt4 book ai didi

c# - 使用 out/ref 与 return 相比有什么好处?

转载 作者:太空狗 更新时间:2023-10-29 17:48:28 26 4
gpt4 key购买 nike

我正在使用 XNA 框架制作游戏,因此我使用了很多对矢量进行操作的函数。 (特别是 Vector2(64 位结构))。令我困扰的是,大多数方法都是用 ref 和 out 参数定义的。这是一个例子:

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

我也觉得有点奇怪。还有一个更明显的Min

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

基本上,几乎所有的函数都有 refout 的重载。类似,其他APIs .

这种设计的好处是什么? XNA 针对性能进行了优化,这可能是结果吗?比方说,四元数需要 128b,其中通过 ref 较少。

编辑:

这是一个测试代码:

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

结果:

  • refOut1 2200
  • refOut2 1400

Win 7 64 位,.Net 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

开销似乎是由 temp Vector 引起的。我还尝试了 1GHz WP 7.5 设备:

  • 1979
  • 1677

迭代次数减少一个数量级的刻度数。

最佳答案

Vector2 是一个结构,这意味着当它作为值返回时,返回一个副本,而不是返回对现有结构的引用。通过使用 ref/out 参数,您可以避免此复制,以便在 Min 方法中创建的向量是您的 result 变量中的精确向量。

这是通常不鼓励的微优化之一,但在游戏世界中它已经足够频繁,并且在性能足够重要的环境中,它值得可读性稍差的选项。

关于c# - 使用 out/ref 与 return 相比有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10541532/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com