使用 out/ref 与返回相比有什么好处?

2023-11-27

我正在使用 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);

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

这样的设计有什么好处呢?XNA 针对性能进行了优化,这可能是一个结果吗?比如说,四元数需要 128b,其中传递的 ref 较少。

EDIT:

这是一个测试代码:

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

结果:

  • 参考输出1 2200
  • 参考输出2 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

and

.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多变的。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 out/ref 与返回相比有什么好处? 的相关文章

  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • C++ 多行字符串原始文字[重复]

    这个问题在这里已经有答案了 我们可以像这样定义一个多行字符串 const char text1 part 1 part 2 part 3 part 4 const char text2 part 1 part 2 part 3 part 4
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • ASP.NET Core 3.1登录后如何获取用户信息

    我试图在登录 ASP NET Core 3 1 后获取用户信息 如姓名 电子邮件 id 等信息 这是我在登录操作中的代码 var claims new List
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • VB.NET 中的静态方法实现

    我很困惑Static在 VB NET 中的实现 在 C 中 我们可以创建静态类和静态方法来为我们的应用程序编写实用方法 现在 VB NET 让我们创建Module代替静态类 如果我们在模块中创建一个方法 默认情况下它会变成静态的 但在我的应
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • SoftLayer_Account::getOperatingSystemReloadImages

    我想在 OSReload 期间使用 API 获取可用操作系统列表 我发现提到了 SoftLayer Account getOperatingSystemReloadImages 方法 但找不到该方法的用法 谁能帮我解决这个问题 谢谢 我找不
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template

随机推荐

  • 使关键字自动全局链接

    有没有办法让单词的每个实例自动变成链接 例如 每次我写 apple 时 它都会自动格式化为 a href www apple com class whatever target blank apple a 我假设我可以使用 javascri
  • Seaborn load_dataset

    我正在尝试使用 Seaborn 按照以下方式进行分组箱线图工作example 我可以让上面的例子工作 但是行 tips sns load dataset tips 根本没有解释 我已经找到 Tips csv 文件 但我似乎无法找到有关 lo
  • 使用 Criteria API 的动态 JPA 2.0 查询

    我在使用 JPA 2 0 的 CriteriaBuilder 构建动态查询时有点卡住了 我猜想我有一个相当常见的用例 用户提供任意数量的搜索参数 X 和 或连接 例如 select e from Foo where name X1 or n
  • 为什么C++中的静态thread_local对象被构造两次?

    这段代码 include
  • 有 UIView 调整大小事件吗?

    我有一个视图 其中包含图像视图的行和列 如果调整此视图的大小 我需要重新排列图像视图的位置 该视图是另一个已调整大小的视图的子视图 有没有办法检测该视图何时调整大小 正如 Uli 在下面评论的那样 正确的方法是覆盖layoutSubview
  • 如何告诉 Gem 文件使用 gem 的特定本地副本

    假设我有一颗宝石幸福地生活在 MyPath MyGem gem 我想使用本地且独特的 gem 而不是来自 Github 或从任何地方获取的 gem 版本 我如何指定我要使用gem mygem from MyPath MyGem gem 尝试
  • 检测文本是否溢出[重复]

    这个问题在这里已经有答案了 如何检测文本是否溢出 例如 以下文本的长度超出了 div 容器允许的长度 我如何在 JavaScript 中检测到这一点 div style max width 100px Lorem ipsum dolor s
  • 使用快速傅里叶变换分析音频

    我正在尝试用 python 创建图形频谱分析仪 我当前正在读取 16 位双通道 44 100 Hz 采样率音频流的 1024 字节 并对 2 个通道的幅度进行平均 现在我有 256 条签名短裤 我现在想使用 numpy 之类的模块对该数组执
  • PHP - 理解create_function() - 传递简单变量

    我第一次尝试使用动态create function 到目前为止 还没有取得多大成功 我的功能是这样的 function o99 brsa custom widgets global wp meta boxes global o99 brsa
  • 返回捕获局部变量的 lambda

    今天我在 C 11 lambda 中遇到了一个非常不直观的行为 至少对我来说 有问题的代码如下 include
  • WinDbg 没有告诉我字符串的根位置

    我试图找出为什么字符串在我的应用程序中存储了这么长的时间 并占用了过多的内存 我有一个定期运行的 Windows 服务 它从数据库 以 DataSet 的形式 读取数据 然后进行一些处理 全部由 NET 托管 Windows 服务每 5 分
  • 针对多个字段的 LINQ string[]

    假设我有一个包含以下字段的表 dataContext Customer FName varchar LName varchar Phone varchar DOB datetime Address varchar 该表填充了一些示例数据 可
  • Spark 使用 sc.textFile("s3a://bucket/filePath") 读取 s3。 java.lang.NoSuchMethodError:com.amazonaws.services.s3.transfer.TransferMana

    我已将自爆罐子添加到 Spark jars 路径中 hadoop aws 2 7 3 jar aws java sdk s3 1 11 126 jar aws java sdk core 1 11 126 jar 火花2 1 0 在 Spa
  • 将托管 bean 属性注入自定义转换器

    如何将托管 bean 的属性注入自定义转换器 例如 一个通用列表 以便我可以从转换器内的列表中提取我的对象 在某些情况下 当您需要将诸如 ManagedBean EJB 等 Bean 注入到Converter or a Validator
  • 当我尝试在 Web 应用程序中创建超过 250 个线程时,我收到 Cannot get a connection, pool error Timeout waiting foridle object [重复]

    这个问题在这里已经有答案了 可能的重复 连接池异常 无法获取连接 池错误等待空闲对象超时 当我尝试在 Web 应用程序中创建超过 250 个线程时 出现无法获取连接 池错误超时等待空闲对象错误 我正在使用 JSF 2 0 和 Hiberna
  • 使用实体框架更新语句

    简单的问题 在更新一个实体时是否可以使用实体框架实现此查询 update test set value value 1 where id 10 使用批量更新功能实体框架扩展库 像这样 dbContext Tests Update t gt
  • 在同一选择中使用列别名[重复]

    这个问题在这里已经有答案了 如何在同一查询的其他地方使用列别名 在Oracle中可以吗 使用 EMP ID 的示例 SELECT t1 DATE t2 NAME t1 ID TO NUMBER SUBSTR t1 NUMBER ID 6 T
  • 6 种基本算术运算的相对周期时间是多少?

    当我尝试优化我的代码时 很长一段时间我一直在使用一条经验法则 即加法和减法的值是 1 乘法和除法的值是 3 平方的值是 3 我很少使用更通用的规则 pow函数 所以我没有经验法则 平方根值 10 我假设数字的平方只是乘法 所以值 3 这是二
  • 如何从“签出但已删除”状态恢复文件?

    我试图签出一个文件 它进入 签出但已删除 状态 我无法撤消结账 也不知道下一步需要做什么 当我为此上网时 我发现了一篇文章IBM 网站结帐但已删除状态 但我没有尝试重命名文章中提到的文件名 但仍然出现错误 我使用的是 Clearcase 7
  • 使用 out/ref 与返回相比有什么好处?

    我正在使用 XNA 框架制作游戏 因此我使用了很多对向量进行操作的函数 尤其Vector2 64 位结构 让我困扰的是大多数方法都是用 ref 和 out 参数定义的 这是一个例子 void Min ref Vector2 value1 r