什么是使用了/ REF回访的好处? [英] What is the benefit of using out/ref versus returning?

查看:229
本文介绍了什么是使用了/ REF回访的好处?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在做一个游戏使用XNA框架,所以我使用的向量操作很多功能。 (特别是 Vector2 (64位结构))。让我困扰的是,大多数的方法是用ref和out参数来定义。下面是一个例子:

I'm making a game using XNA framework, so I use a lot functions that operate on vectors. (especially Vector2 (64bit struct)). What bothers me is that most of the methods are defined with ref and out parameters. Here is an example:

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

这看起来有点怪过我。也有另一种最小这是比较明显的。

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

基本上,几乎所有的功能都重载与 REF 退出秒。类似的,其他的API

Basically, almost all the functions have overloads with refs and outs. Similar, other APIs.

什么是这种设计的好处? XNA针对性能进行了优化,可以说,它是一个结果呢?我说,四元数需要128B在由裁判通过更少。

What is the benefit of this design? XNA is optimized for performance, could it be a result? Say, Quaternion requires 128b where passing by ref less.

编辑:

下面是测试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);
    }
}

结果:

  • refOut1 2200
  • refOut2 1400

Win 7的64位,.NET 4 XNA 4.0

Win 7 64bit, .Net 4. XNA 4.0

此外IL 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

.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的设备:

Seems overhead is caused by temp Vector. Also I tried 1GHz WP 7.5 device:

  • 在1979年
  • 1677

刻度线数目为迭代幅度较小数量的订单。

Number of ticks for an order of magnitude smaller number of iterations.

推荐答案

Vector2是一个结构,这意味着当它返回一个值的副本返回,而不是返回一个参考现有结构。通过使用REF / out参数就可以避免这个副本,以便在最小方法创建的载体是在你的结果的精确矢量变量。

Vector2 is a struct, which means that when it's returned as a value a copy is returned, rather than returning a reference to an existing structure. By using ref/out parameters you can avoid this copy so that the Vector created in the Min method is the exact vector in your result variable.

这是那些微的优化通常会气馁,但是在游戏的世界,它的完成往往不够,而且在环境中的性能重要的是,它是值得的略少可读性选项。

It's one of those micro optimization that normally would be discouraged, but in the game world it's done often enough, and in environments where performance matters enough, that it's worth the slightly less readable option.

这篇关于什么是使用了/ REF回访的好处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆