gpt4 book ai didi

c# - 显示转换为 uint 的代码示例比范围检查更有效

转载 作者:太空狗 更新时间:2023-10-29 19:53:39 26 4
gpt4 key购买 nike

所以我在看this question并且普遍的共识是 uint 转换版本比使用 0 进行范围检查更有效。由于代码也在 MS 的 List 实现中,我认为这是一个真正的优化。但是,我未能生成可以为 uint 版本带来更好性能的代码示例。我尝试了不同的测试,但缺少某些东西,或者我的代码的其他部分使检查时间相形见绌。我最后一次尝试是这样的:

class TestType
{
public TestType(int size)
{
MaxSize = size;
Random rand = new Random(100);
for (int i = 0; i < MaxIterations; i++)
{
indexes[i] = rand.Next(0, MaxSize);
}
}

public const int MaxIterations = 10000000;
private int MaxSize;
private int[] indexes = new int[MaxIterations];

public void Test()
{
var timer = new Stopwatch();

int inRange = 0;
int outOfRange = 0;

timer.Start();
for (int i = 0; i < MaxIterations; i++)
{
int x = indexes[i];
if (x < 0 || x > MaxSize)
{
throw new Exception();

}

inRange += indexes[x];
}
timer.Stop();

Console.WriteLine("Comparision 1: " + inRange + "/" + outOfRange + ", elapsed: " + timer.ElapsedMilliseconds + "ms");

inRange = 0;
outOfRange = 0;

timer.Reset();
timer.Start();

for (int i = 0; i < MaxIterations; i++)
{
int x = indexes[i];
if ((uint)x > (uint)MaxSize)
{
throw new Exception();
}

inRange += indexes[x];
}

timer.Stop();

Console.WriteLine("Comparision 2: " + inRange + "/" + outOfRange + ", elapsed: " + timer.ElapsedMilliseconds + "ms");

}
}

class Program
{
static void Main()
{
TestType t = new TestType(TestType.MaxIterations);
t.Test();
TestType t2 = new TestType(TestType.MaxIterations);
t2.Test();
TestType t3 = new TestType(TestType.MaxIterations);
t3.Test();
}
}

代码有点乱,因为我尝试了很多方法来使 uint 检查执行得更快,例如将比较变量移动到类的字段中,生成随机索引访问等等,但在每种情况下结果似乎都是两个版本都一样。那么这种变化是否适用于现代 x86 处理器,有人可以以某种方式证明它吗?

请注意,我并不是要找人修理我的 sample 或解释它有什么问题。我只想看看优化确实起作用的情况。

最佳答案

       if (x < 0 || x > MaxSize)

比较是由CMP处理器指令(Compare)进行的。你会想看看 Agner Fog's instruction tables document (PDF),它列出了说明的费用。在列表中找到您的处理器,然后找到 CMP 指令。

对于我的 Haswell,CMP 需要 1 个周期的延迟和 0.25 个周期的吞吐量。

像这样的分数成本可以用一个解释,Haswell 有 4 个整数执行单元,可以同时执行指令。当一个程序包含足够多的整数操作时,如 CMP,没有相互依赖性,那么它们可以同时执行。实际上使程序快 4 倍。你并不总是设法让所有 4 个同时忙于你的代码,这实际上是非常罕见的。但是在这种情况下,您确实让其中的 2 个忙。或者换句话说,两次比较所花费的时间与一次比较所花费的时间一样长,即 1 个周期。

还有其他因素在起作用,使执行时间相同。一件有帮助的事情是处理器可以很好地预测分支,它可以推测性地执行 x > MaxSize,尽管有短路评估。事实上,它最终会使用结果,因为分支从未被采用。

这段代码的真正瓶颈是数组索引,访问内存是处理器可以做的最慢的事情之一。因此,“快速”版本的代码并没有更快,尽管它提供了更多允许处理器并发执行指令的机会。无论如何,今天这不是什么好机会,处理器有太多的执行单元而无法保持忙碌。否则,使超线程工作的功能。在这两种情况下,处理器都以相同的速度陷入困境。

在我的机器上,我必须编写占用超过 4 个引擎的代码以使其变慢。像这样愚蠢的代码:

     if (x < 0 || x > MaxSize || x > 10000000 || x > 20000000 || x > 3000000) {
outOfRange++;
}
else {
inRange++;
}

使用 5 次比较,现在我可以区分 61 与 47 毫秒。或者换句话说,这是一种计算处理器中整数引擎数量的方法。呵呵:)

所以这是一个 微观优化,可能在十年前就已经取得了返回。现在没有了。把它从你要担心的事情 list 上划掉:)

关于c# - 显示转换为 uint 的代码示例比范围检查更有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29378837/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com