为什么一个简单的 get 语句这么慢?

2024-04-24

几年前,我在学校接到一项作业,必须并行化光线追踪器。
这是一项简单的任务,我真的很喜欢做它。

今天,我想对光线追踪器进行分析,看看是否可以让它运行得更快(无需完全修改代码)。在分析过程中,我注意到一些有趣的事情:

    // Sphere.Intersect
    public bool Intersect(Ray ray, Intersection hit)
    {
        double a = ray.Dir.x * ray.Dir.x +
                   ray.Dir.y * ray.Dir.y +
                   ray.Dir.z * ray.Dir.z;
        double b = 2 * (ray.Dir.x * (ray.Pos.x - Center.x) +
                        ray.Dir.y * (ray.Pos.y - Center.y) +
                        ray.Dir.z * (ray.Pos.z - Center.z));
        double c = (ray.Pos.x - Center.x) * (ray.Pos.x - Center.x) +
                   (ray.Pos.y - Center.y) * (ray.Pos.y - Center.y) +
                   (ray.Pos.z - Center.z) * (ray.Pos.z - Center.z) - Radius * Radius;

        // more stuff here
    }

根据分析器,25% 的 CPU 时间花费在get_Dir and get_Pos,这就是为什么,我决定通过以下方式优化代码:

    // Sphere.Intersect
    public bool Intersect(Ray ray, Intersection hit)
    {
        Vector3d dir = ray.Dir, pos = ray.Pos;
        double xDir = dir.x, yDir = dir.y, zDir = dir.z,
               xPos = pos.x, yPos = pos.y, zPos = pos.z,
               xCen = Center.x, yCen = Center.y, zCen = Center.z;

        double a = xDir * xDir +
                   yDir * yDir +
                   zDir * zDir;
        double b = 2 * (xDir * (xPos - xCen) +
                        yDir * (yPos - yCen) +
                        zDir * (zPos - zCen));
        double c = (xPos - xCen) * (xPos - xCen) +
                   (yPos - yCen) * (yPos - yCen) +
                   (zPos - zCen) * (zPos - zCen) - Radius * Radius;

        // more stuff here
    }

取得了惊人的结果。

在原始代码中,使用默认参数运行光线追踪器(创建仅使用直接闪电且没有 AA 的 1024x1024 图像)将需要〜88秒.
在修改后的代码中,同样需要比60秒.
只需对代码进行一点修改,我就实现了约 1.5 的加速。

起初,我以为吸气剂是Ray.Dir and Ray.Pos我们在幕后做一些事情,这会减慢程序的速度。

以下是两者的吸气剂:

    public Vector3d Pos
    {
        get { return _pos; }
    }

    public Vector3d Dir
    {
        get { return _dir; }
    }

所以,两者都返回一个 Vector3D,仅此而已。

我真的很想知道,调用 getter 怎么会比直接访问变量花费更长的时间。

是因为CPU缓存变量吗?或者重复调用这些方法的开销可能会增加?或者也许 JIT 处理后一种情况比前一种情况更好?或者也许还有其他我没有看到的东西?

任何见解将不胜感激。

Edit:

正如@MatthewWatson 所建议的,我使用了StopWatch在调试器之外计时发布版本。为了消除噪音,我多次进行了测试。结果,前面的代码需要〜21秒(20.7 和 20.9 之间)完成,而后者仅〜19秒(19 和 19.2 之间)。
差异已经变得可以忽略不计,但仍然存在。


介绍

我敢打赌,由于 C# 中涉及类型结构属性的怪癖,原始代码要慢得多。这并不完全直观,但这种类型的属性本质上很慢。为什么?因为结构体不是通过引用传递的。所以为了访问ray.Dir.x, 你必须

  1. 加载局部变量ray.
  2. Call get_Dir并将结果存储在临时变量中。这涉及复制整个结构,即使只使用了字段“x”。
  3. 访问字段x从临时副本。

查看原始代码,get 访问器被调用了 18 次。这是一个巨大的浪费,因为这意味着整个结构体总共被复制了 18 次。在您的优化代码中,只有两个副本 -Dir and Pos两者都只被调用一次;进一步访问这些值仅包含上面的第三步:

  1. 访问字段x从临时副本。

总而言之,结构和属性不能放在一起。

为什么 C# 对结构体属性有这样的行为?

这与 C# 中结构是值类型这一事实有关。您正在传递值本身,而不是指向该值的指针。

为什么编译器不能识别 get 访问器只是返回一个字段,并完全绕过该属性?

在调试模式下,会跳过此类优化以提供更好的调试体验。即使在发布模式下,您也会发现大多数抖动通常不会这样做。我不知道确切的原因,但我相信这是因为该字段并不总是字对齐的。现代 CPU 有奇怪的性能要求。 :-)

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

为什么一个简单的 get 语句这么慢? 的相关文章

  • 结构体如何存储在内存中?

    我有一个struct iof header在我的代码中 我确定它的宽度是 24 字节 我执行 sizeof iof header 它返回 32 字节宽 问题1为什么是 32 字节宽而不是 24 字节宽 问题2包括其成员在内 结构体如何存储在
  • fopen_s 怎么会比 fopen 更安全呢?

    我正在处理遗留代码Windows平台 当我编译代码时VS2013 它给出以下警告 错误 C4996 fopen 该函数或变量可能不安全 考虑使用fopen s反而 要禁用弃用 请使用 CRT SECURE NO WARNINGS 详情请参见
  • .crt 部分?这个警告是什么意思?

    我最近收到此警告 VC 2010 warning LNK4210 CRT section exists there may be unhandled static initializers or terminators 我假设这是关键部分
  • STL之类的容器typedef快捷方式?

    STL 容器的常见模式是这样的 map
  • 将字符串作为 PChar 从 CSharp 传递到 Delphi DLL

    我正在尝试将字符串从 C 传递到 Delphi 构建的 DLL Delphi DLL 需要 PChar 这是Delphi导出 procedure DLL Message Location PChar AIntValue integer st
  • 使用 C# 将多个音频样本混合到单个文件中

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个能够创建音频文件 mp3 或 wav 的库 NAudio http www codeple
  • 嵌入资源文件的路径

    我的资源文件中有一个图标 我想引用它 这是需要图标文件路径的代码 IWshRuntimeLibrary IWshShortcut MyShortcut MyShortcut IWshRuntimeLibrary IWshShortcut W
  • 将 dataGridView 中选定的行作为对象检索

    我有一堂这样的课 public partial class AdressBokPerson public long Session get set public string F rnamn get set public string Ef
  • 如何自定义 Google 测试失败消息?

    我编写了一个如下所示的 Google 测试 它将一些计算值与 CSV 文件中预期存储的值进行比较 class SampleTest public testing Test public void setupFile const std st
  • 我可以将 UseCSharpNullComparisonBehavior 用于单个查询吗?

    我有一个查询 该查询曾经是存储过程 现已转换为 EF 查询 现在已经超时了 使用 SQL Profiler 我可以看到生成的 SQL 的唯一区别是 EF 转变的新行为entity Property value into entity Pro
  • 在 C# 中使用命名空间别名有什么好处? [复制]

    这个问题在这里已经有答案了 使用命名空间别名有什么好处 仅仅是为了简化编码吗 仅当与类发生冲突时我才使用名称空间别名 对我来说 这根本没有简化 我的意见是 如果没有必要 就不要使用
  • 如何在 C# 中更改公共 IP 地址

    我正在创建一个 C winform 应用程序 我想在其中更改公共 IP 地址 而不是像 Hotspot Shield ZenMate OpenVPN 等那样更改 IPv4 地址 我已经检查了以下链接 但没有找到足够的帮助 所以我发布了这个问
  • 从 DataRow 单元格解析 int [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 如何从 DataRow 单元格解析 int 值 Int32 Parse item QuestionId ToString 这段代码可以工作 但看
  • 传递数组时在 C 中的函数参数中强制指定数组大小

    Context 在 C 中 我有一个以数组作为参数的函数 该参数用作该函数的输出 输出的大小始终相同 我会 让阅读代码的人清楚所需的大小 不过它已经在函数注释中了 理想情况下 编译会输出警告或错误 这样我就可以在编译时而不是运行时防止出现问
  • Gremlin.net 文本包含等效项

    我正在使用 Gremlin net 库连接到 janus 图形服务器 我使用 cassandra 和弹性搜索进行数据存储和索引 在我使用的 gremlin 语言和 gremlin 控制台中文本包含在属性的文本中进行搜索 我正在使用混合索引
  • 如何将System.Windows dll添加到Visual Studio 2010 Express?

    我正在开发一个小型应用程序C and VS2010 as IDE with NET框架4 我想用CaptureSource类以便从笔记本电脑的网络摄像头捕获视频 为此我需要添加一个命名空间System Windows DependencyO
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • C 变量声明的效率 [重复]

    这个问题在这里已经有答案了 例如 在 C 中声明一个变量需要多长时间int x or unsigned long long var 我想知道它是否会让我的代码在类似的事情中更快 for conditions int var 0 code 这
  • Xcode 7 调试器不会中断内联标头函数

    过去五年我一直在各种 C 项目中使用 Xcode 没有出现这个问题 今天 我打开了一个较旧的项目 大约 2 年前 并尝试通过在该函数中放置一个活动断点来调试头文件中的内联函数 由于某种原因 调试器不会中断此代码 但是 如果我在调用该函数的
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加

随机推荐

  • 为什么最好使用 Glib 数据类型(例如 `gint` 而不是 `int`)? [复制]

    这个问题在这里已经有答案了 可能的重复 为什么glib要重新定义类型 https stackoverflow com questions 1819561 why does glib redefine types 在 GTK 2 0 教程中
  • 用于计算机安全的遗传算法[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在为大学选择项目 我对遗传算法和计算机安全的结合非常感兴趣 因此我的问题是 是否可以使用GAany计算机安全方面 例如 我正在考虑
  • Chrome 浏览器在从 selenium 加载后立即关闭

    我正在运行一个基本的 python 程序来打开 Chrome 窗口 但是一旦代码执行 该窗口就会在那里停留一秒钟 然后立即关闭 from selenium import webdriver import time browser webdr
  • 如何组合杜松子酒中的路线组? [复制]

    这个问题在这里已经有答案了 我创建了两个不同的组gin具体路由 user and todo在两个不同的包中 我想将它们合并到一个文件中 这是我的userroutes go file package userrouter import git
  • 为复合对象编写比较器以进行二分搜索

    我有一个类和实例列表 看起来像这样 字段名称已更改以保护无辜 专有 public class Bloat public long timeInMilliseconds public long spaceInBytes public long
  • 使用 3DES 和 CBC 损坏的加密数据的前 8 个字节

    我在应用程序中使用 PyCrypto 来加密数据 但由于某种原因 无论我做什么 前 8 个字节 对应于第一个块 都会损坏 gt gt gt from Crypto Cipher import DES3 gt gt gt from Crypt
  • Rust 中的基本树和指针

    我拥有一些 C 语言背景 尝试 学习 Rust 让我对自己的能力产生了质疑 我正在尝试找出如何更改拥有的指针 并且正在努力做到这一点 除了从额外的库中复制之外 我无法弄清楚二叉树上所需的递归 特别是 我不知道如何交换指针分支 虽然使用链表我
  • 在 DNN 模块中执行 .exe

    我试图让我的 DNN 模块 6 1 3 在程序中发生特定条件时启动任何类型的可执行文件 此时我只是尝试让它运行记事本并创建一个文本文件 这就是我现在正在尝试的 ProcessStartInfo pi new ProcessStartInfo
  • SASS:直系后代规则?

    如何在 SASS 中表示直接后代 CSS 规则 Ex body gt div 在文档中似乎找不到它 http sass lang com docs yardoc file SASS REFERENCE html http sass lang
  • 将 Google 自定义搜索添加到 AMP 网站

    我有我的 Google 自定义搜索引擎 GCSE 代码
  • pip + requests.txt:奇怪的行为。不断下载各种版本的pandas

    这是用 pip 和 pandas 观察到的情况 以下是我的要求 txt asgiref 3 3 1 auditlog3 1 0 1 click 7 1 2 auditlog3 dj database url 0 5 0 Django 3 1
  • NSLog 上的 EXC_BAD_ACCESS 没有字符串格式

    我在以下代码行中收到 EXC BAD ACCESS 或 malloc 错误 NSLog Points 这对我来说毫无意义 因为它应该访问字符串常量而不是其他任何东西 通常是 EXC BAD ACCESS 但偶尔会出现以下错误 在同一行 An
  • scanf:内部带有宏(#define 常量)的模板

    我有一些像这样的代码 define MAXSIZE 100 int main char str MAXSIZE 1 scanf 100s str 问题是我仍然有 幻数 100 尽管定义了 MAXSIZE 有没有办法正确地将 MAXSIZE
  • 如何在 Symfony2 控制台命令中设置环境

    希望这是一个简单的问题 在 Symfony2 中运行控制台命令时如何指定使用哪个环境 我创建了一些命令 但是我想在我的临时服务器上的 临时 环境上下文中运行它们 在生产服务器上时在 产品 环境中运行它们 不同的环境定义不同的数据库连接 如何
  • 如何使用 Log4cxx 或 log4j 记录进程 ID

    我正在使用 log4cxx 我的项目 我可以使用 t 标记记录当前线程 id 如何在其中记录进程 id 或 log4j 我正在使用 ConversionPattern 和基于 xml 的配置文件 谢谢 基于以上答案 我将在 log4j 中执
  • 如何修复此警告“useLayoutEffect”相关警告?

    我将 NextJS 与 Material UI 和 Apollo 结合使用 虽然一切正常 但警告没有消失 在我看来 很多 Material UI 组件都在使用使用布局效果React 会发出警告 错误如下 警告 useLayoutEffect
  • ReferenceError:使用 CKEditor 时未定义 self [重复]

    这个问题在这里已经有答案了 ReferenceError 导入 CKEditor 时未定义 self 我正在使用 next js import CKEditor from ckeditor ckeditor5 react 已经安装使用 np
  • float 和 double 精度相关的概念

    为什么精度float小数点后最多 6 位 精度double小数点后最多15位 任何人都可以给一个数学解释 of it 说一下精度float or double是一些小数位数是草率的术语 float and double通常使用 IEEE 7
  • 输入具有最小和最大数字的值

    下面是一个输入数字表单 我使用 JavaScript 添加了一些代码 其中可写入的最小数字为 1 最大可写入数字为 50 当有人尝试输入任何小于 1 且大于 50 的数字时 它会自动将其替换为数字 1 或 50 但我没有成功实现此目标 我需
  • 为什么一个简单的 get 语句这么慢?

    几年前 我在学校接到一项作业 必须并行化光线追踪器 这是一项简单的任务 我真的很喜欢做它 今天 我想对光线追踪器进行分析 看看是否可以让它运行得更快 无需完全修改代码 在分析过程中 我注意到一些有趣的事情 Sphere Intersect