c# - 为什么在这种情况下为 for 循环使用指针性能更高?

标签 c# performance pointers unsafe unsafe-pointers

我没有 C/C++ 或相关低级语言的背景,所以我以前从未遇到过指针。我是一名主要在 C# 中工作的游戏开发人员,今天早上我终于决定将代码的一些性能关键部分转移到不安全的上下文中(并且请不要“不要使用不安全”的答案,因为我已经阅读了很多次在做研究的时候,因为它在某些领域已经让我获得了大约 6 倍的性能,到目前为止没有任何问题,而且我喜欢能够在没有分配的情况下做像反向数组这样的事情)。无论如何,在某些情况下我预计不会有任何差异,甚至可能会降低速度,而且我在现实中节省了很多滴答声(在某些情况下我说的是双倍速度)。这种好处似乎随着迭代次数的增加而减少,对此我并不完全理解。

情况是这样的:

int x = 0;
for(int i = 0; i < 100; i++)
    x++;

平均需要 15 个滴答。

编辑:以下是不安全的代码,但我认为这是给定的。

int x = 0, i = 0;
int* i_ptr;
for(i_ptr = &i; *i_ptr < 100; (*i_ptr)++)
    x++;

平均需要大约 7 个刻度。

正如我提到的,我没有低级背景,而且我今天早上才开始使用指针,至少是直接使用,所以我可能遗漏了很多信息。所以我的第一个问题是——为什么在这种情况下指针的性能更高?这不是一个孤立的实例,当然还有很多其他变量,在与 PC 相关的特定时间点,但我在大量测试中得到的这些结果非常一致。

在我看来,操作是这样的:

没有指针:

  • 获取i的地址
  • 获取地址的值(value)

指针:

  • 获取i_ptr的地址
  • 从i_ptr获取i的地址
  • 获取地址的值(value)

在我看来,在这里使用指针肯定会有更多的开销,无论多么可笑地可以忽略不计。在这种情况下,指针如何始终比直接变量更高效?当然,这些也都在堆栈上,所以据我所知,这与它们最终存储的位置无关。

如前所述,需要注意的是此奖励会随着迭代次数的增加而减少,而且速度非常快。我从以下数据中删除了极端值以考虑背景干扰。

在 1000 次迭代时,它们在 30 到 34 个刻度处是相同的。

在 10000 次迭代时,指针会慢大约 20 个刻度。

跳到 10000000 次迭代,指针慢了大约 10000 ticks 左右。

我的假设是减少来 self 之前介绍的额外步骤,假设有一个额外的查找,这让我想知道为什么它在低时更多有指针的性能循环计数。至少,我假设它们或多或少是相同的(我想它们在实践中是相同的,但是与数百万次重复测试相差 8 个刻度对我来说是非常确定的)直到我的非常粗略的阈值发现介于 100 到 1000 次迭代之间。

如果我有点吹毛求疵,或者这是一个糟糕的问题,我深表歉意,但我觉得确切地知道幕后发生的事情似乎是有益的。如果不出意外,我认为这非常有趣!

最佳答案

一些用户认为测试结果很可能是由于测量不准确造成的,至少在某种程度上看起来是这样。当对一千万个连续测试进行平均时,两者的平均值通常是相等的,尽管在某些情况下,指针的使用会产生额外的滴答声。有趣的是,当作为单个案例进行测试时,使用指针的执行时间始终低于不使用指针的情况。当然,在尝试测试的特定时间点,还有很多其他变量在起作用,这使得进一步追踪这一点变得毫无意义。但结果是我学到了更多关于指针的知识,这是我的主要目标,所以我对测试很满意。

关于c# - 为什么在这种情况下为 for 循环使用指针性能更高?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42513804/

相关文章:

c# - 需要 Body 标签内的数据,但不需要任何其他标签

c# - String.Contains() 比在字符串中遍历整个 char 数组快吗?

可以期望 C 数组具有与结构相同的性能吗?

c++ - 随机完整系统无响应运行数学函数

c++ - 链表值 C++ 的问题

c++ - 如何在 C++ 中将 int[][] 转换为 int**

c# - HashSet (.NET4) 不会忽略 c# 中的重复项

c# - Kusto 客户端无法向服务 : Request headers must contain only ASCII characters 发送请求

c# - 如何缓存具有多个属性的对象

c - 如何将一个 char* 分配给另一个 char*