Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么一个简单的get语句这么慢?_C#_Getter - Fatal编程技术网

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

C# 为什么一个简单的get语句这么慢?,c#,getter,C#,Getter,几年前,我在学校接受了一项作业,在那里我必须将光线跟踪器并行化。 这是一项简单的任务,我真的很喜欢做它 今天,我想分析一下raytracer,看看是否可以让它运行得更快(而不需要彻底修改代码)。在分析过程中,我注意到了一些有趣的事情: // Sphere.Intersect public bool Intersect(Ray ray, Intersection hit) { double a = ray.Dir.x * ray.Dir.x +

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

今天,我想分析一下raytracer,看看是否可以让它运行得更快(而不需要彻底修改代码)。在分析过程中,我注意到了一些有趣的事情:

    // 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
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
    }
结果惊人

在原始代码中,使用其默认参数运行光线跟踪器(创建一个只有direct lightning且没有AA的1024x1024图像)将花费~88秒
在修改后的代码中,同样的操作只需要不到60秒的时间 只需对代码进行一点修改,我就实现了~1.5的加速

起初,我认为
Ray.Dir
Ray.Pos
的getter在幕后做了一些事情,这会减慢程序的速度

以下是这两种方法的要点:

    public Vector3d Pos
    {
        get { return _pos; }
    }

    public Vector3d Dir
    {
        get { return _dir; }
    }
所以,两者都返回一个向量3D,就是这样

我真的很想知道,调用getter比直接访问变量要花那么长的时间

是因为CPU缓存变量吗?或者反复调用这些方法的开销加起来了?或者JIT处理后一种情况比前者更好?或者也许还有什么我看不到的

如有任何见解,将不胜感激

编辑: 正如@matthewatson所建议的,我使用了一个
StopWatch
在调试器之外定时发布构建。为了消除噪音,我运行了多次测试。因此,前一个代码需要~21秒(介于20.7和20.9之间)才能完成,而后一个代码只需要~19秒(介于19和19.2之间)。
差异已经变得微不足道,但仍然存在。

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

  • 加载局部变量
    ray
  • 调用
    get_Dir
    并将结果存储在临时变量中。这涉及复制整个结构,即使只使用了字段“x”
  • 从临时副本访问字段
    x
  • 查看原始代码,get访问器被调用了18次。这是一个巨大的浪费,因为这意味着整个结构被复制了18次。在优化的代码中,只有两个副本-
    Dir
    Pos
    都只调用一次;进一步访问这些值仅包括上述第三步:

  • 从临时副本访问字段
    x
  • 总而言之,结构和属性并不同时存在

    为什么C#在结构属性中会有这种行为? 这与C#中的结构是值类型这一事实有关。您传递的是值本身,而不是指向该值的指针

    为什么编译器不认识到get访问器只是返回一个字段,并一起绕过属性?
    在调试模式下,将跳过类似的优化以提供更好的去贝格体验。即使在发布模式下,您也会发现大多数的不安通常不会这样做。我不知道确切的原因,但我相信这是因为字段并不总是单词对齐的。现代CPU有奇怪的性能要求。:-)

    您是否使用秒表来计时从任何调试器外部运行的发布版本?(如果不是,你应该!)发布版本应该内联简单的getter,但调试版本不会。@MatthewWatson我确实使用秒表,但88秒和60秒来自分析器
    Analyze->Start Performance Analysis Alt+F2
    ->
    挂钟时间(秒)
    使用调试版本。您必须对发布版本计时才能获得正确的结果。正如我所说,调试版本不内联简单的属性获取程序和设置程序,而发布版本则内联简单的属性获取程序和设置程序。(顺便说一句,我说的是抖动,不是IL代码。)我认为这将对这个特定代码产生巨大的影响。@MatthewWatson谢谢你的提示。我按照你的建议做了,得到了一些更一致的结果。有了优化,代码运行需要约19秒,而没有优化则需要约21秒。尽管差异可以忽略不计,但仍然存在差异。也许还可以尝试将
    (xPos-xCen)
    (以及相关的)表达式移动到局部变量中。计算三次没有意义。编辑:如果它们是结构,则通过属性检索它们可能需要更长的时间,因为每次点击属性时,它都会将结构复制到一个全新的结构。(请记住,属性只是一个方法)