【问题标题】:Optimisation of threshold computation阈值计算的优化
【发布时间】:2026-01-06 02:40:01
【问题描述】:

我正在尝试优化以下 C# 代码,它根据阈值将字节设置为 0x000xFF

for (int i = 0; i < veryLargeNumber; i++)
{
    data[i] = (byte)(data[i] < threshold ? 0 : 255);
}

Visual Studio 的性能分析器显示,上述代码相当昂贵,需要将近 8 秒的时间来计算 - 占我总处理费用的 98%。我正在处理不到 1000 件商品,因此加起来需要两个多小时。

我认为问题与三元条件运算符有关,因为它会导致分支。我想某种纯数学运算可能会快得多,因为它对 CPU 缓存友好。

有没有办法优化这个?如果有帮助,我可以修复阈值。我认为任何高于约 7% 的性能提升都是胜利,因为总处理时间减少了整整 10 分钟。

【问题讨论】:

  • 你看过为此制作的 IL 吗?
  • @DarenThomas 不,这对我也没有多大用处,因为我对 IL 了解不多。但是,如果它是 x86 程序集,我会很好! ^_^
  • 它们不可能是 那个 不同的 ;) 但是 JIT 真的应该能够将它编译得非常快 - 你可以尝试将结果存储在一个单独的数组中吗?这可能会使优化更容易,因为优化器不必担心您更改输入数组。但我在这里谈论我不太了解的东西。不过,我赞成并行化的建议,因为这是一个非常容易并行化的案例!
  • 我会尝试将(byte) cast 运算符移近实际常量(0 和 255)。这应该可以帮助您避免在每次迭代中强制转换。
  • @Snowbear,实际上,如果进行任何转换,我会感到惊讶 - 编译器应该能够找出 0255 是字节。

标签: c# optimization ternary-operator threshold


【解决方案1】:

如果您使用的是 .NET 4.0 Framework,您可以在以下链接中使用并行库,

http://msdn.microsoft.com/en-us/library/dd460717

在您的情况下,您必须验证阈值,无论如何这需要时间。所以使用线程或 lambda 表达式

【讨论】:

  • 不知道为什么我一开始没有想到使用Parallel。现在每个项目缩短到 5 秒!
【解决方案2】:

只是建议,为此目的使用按位运算符,因为它们更快,以及并行方法。

0x00 = 0000 0000 
0xFF = 1111 1111

尝试使用OR 运算符(即0 | 1 = 1,其中| 代表OR 运算符

编辑:

这是您可以比较哪个数字更大的方法: 让a,b 成为数字:

int temp= a ^ b;
temp|= temp>> 1;
temp|= temp>> 2;
temp|= temp>> 4;
temp|= temp>> 8;
temp|= temp>> 16;

temp&= ~(temp>> 1) | 0x80000000;
temp&= (a ^ 0x80000000) & (b ^ 0x7fffffff);

【讨论】:

  • 我想到了按位运算符,但无法根据输入和阈值提出一个方案,导致 00000000 与 11111111 没有分支。
  • 我的建议是减少分配的篇幅
  • 赋值比按位运算快明显
  • @Polynomial,我认为我们应该比较 bitwise operation VS if statement 而不是比较赋值和按位运算。
  • @Snowbear 这绝对是正确的,如果不是因为它似乎不可能使用cmp 或与位运算符等效。
【解决方案3】:

如果你想要一个按位的解决方案 -

int intSize = sizeof(int) * 8 - 1;
byte t = (byte)(threshold - 1);
for (....)
{
    data[i] = (byte)(255 + 1 ^ ((t - data[i]) >> intSize));
}  

注意:不适用于 0 的极端情况。抱歉

另外,尝试使用 int 数组而不是 byte,看看它是否更快

【讨论】:

  • 速度较慢。使用 int 数组也会消耗当前内存量的 4 倍,考虑到数组已经非常大,这可能是个坏主意。此外,更大的内存分配可能会减慢速度。不过感谢您的尝试。
  • 你确定吗?我刚刚检查了 int.maxvalue/10 的数据,按位似乎需要大约 890 毫秒,而三进制则需要 1200 毫秒