Oke现在显然我可以检查字节数组是否只包含1个值,但我不知道这是否是最快的方法。问题是有时候我会得到一个只有FF(255)值的字节数组,如果发生这种情况我需要在接下来的代码中忽略它,所以我做的事情如下:
var onlyFF = true;
foreach(var value in programCode)
{
if (value != 0xFF)
{
onlyFF = false;
break;
}
}
但这是最快的方式吗?我将不得不检查大量的阵列(尽管(350)所有阵列都非常小)
这是最快的方式还是有更好的方法来做到这一点?
答案 0 :(得分:3)
当然,有更快的方法来优化您正在执行的特定检查。一些评论已经表明的真正问题是它是否真的有必要?是否值得优化查询真的取决于几个问题,你必须首先问自己。
您的表现标准是什么?
您应该每秒处理多少个数组?如果 答案是1000或更少,那我绝对不会打扰 试图优化代码。如果答案是数百万个数组a 第二,那么你可能想考虑做一些表现 测试你的代码。
您期望什么类型的数据?
如果您处理的99%的缓冲区有效(并非所有0xFF字节),那么在大多数情况下,您的循环很可能在前几次检查中存在。如果仅适用于工作量的1%,那么针对最坏情况优化算法是否有意义。
通过更改比较方法,我会为您的代码带来哪些风险?风险大于风险?
Adwaenyth提到的常用优化技术可以应用于您的情况。您可以将字节数组视为long数组,然后使用XOR位逻辑运算符一次比较8个字节。为了有效地使用此方法而无需复制缓冲区,您必须使用不安全的代码。以下示例显示了如何完成此操作的快速而脏的实现(请注意,我没有测试过此代码,所以请不要在没有正确测试的情况下使用):
public static bool IsBufferValidUnSafeXOR(byte[] buffer)
{
bool isValid = false;
int byteLength = buffer.Length;
int base64Length = byteLength >> 3; // same as -- > (int)(byteLength / 8);
int remainingBytes = byteLength - (base64Length << 3);
ulong toggleMask = 0xFFFFFFFFFFFFFFFF;
unsafe
{
fixed (byte* pByteBuffer = buffer)
{
ulong* pBuffer = (ulong*)pByteBuffer;
int index = 0;
while (index < base64Length)
{
if ((pBuffer[index] ^ toggleMask) > 0)
{
isValid = true;
break;
}
index++;
}
}
}
// Check remainder of byte array
if (!isValid)
{
int index = (base64Length << 3);
while(index < byteLength)
{
if (buffer[index] != 0xFF)
{
isValid = true;
break;
}
index++;
}
}
return isValid;
}
我对您当前的非优化方法和优化方法进行了几次性能比较。我在循环中执行每个方法,检查150万个缓冲区的有效性。对于第一次测试,仅检查的5%的缓冲区无效。第二次检查33%的缓冲区对于第3个50%和第4个100%无效。 下表显示了两种方法的比较方式:
---------------------------------------------------------------------------------------------
| Nr | Total Nr. | Valid Buffer | Invalid Buffer | Std Method | XOR Unsafe |
| | Buffers Checked | Count | Count | Execution Time| Execution Time|
---------------------------------------------------------------------------------------------
| 1 | 1,500,00 | 1,425,000 | 75,000 | 183 ms | 124 ms |
---------------------------------------------------------------------------------------------
| 2 | 1,500,00 | 1,000,000 | 500,000 | 566 ms | 226 ms |
---------------------------------------------------------------------------------------------
| 3 | 1,500,00 | 750,000 | 750,000 | 800 ms | 259 ms |
---------------------------------------------------------------------------------------------
| 4 | 1,500,00 | 0 | 1,500,000 | 1574 ms | 431 ms |
---------------------------------------------------------------------------------------------
从上表中我们可以看到,虽然不安全(XOR)方法速度更快,但如果只检查了5%的缓冲区无效,速度差异是微不足道的,而如果100%的缓冲区获得最大的性能提升无效。这让我们回到最初的问题是优化代码真的值得吗?
答案 1 :(得分:1)
使速度更快的一种相当简单的方法是获取数组的ulong*
并一次比较8个字节的块与0xFFFFFFFFFFFFFFFFUL
。您可能需要通过比较字节来处理数组开始和结束时的错位。
然后你可以将循环展开4次,以减少循环开销几乎为零。很快(但可能)比这更快地完成它。
另一个相当简单的选择是在C和PInvoke中编写它。 C编译器有很复杂的方法来实现这一点。 .NET JIT没有。虽然我对neither GCC nor LLVM do any particular tricks here感到惊讶。
使用不同的代码模式LLVM提供以下优化:
if (array[i + 0] & array[i + 1] & array[i + 2] & array[i + 3] == 0xFF)
return true;
这节省了很多指令和分支。
答案 2 :(得分:0)
你可以使用CUDA&#34;只能使用Nvidia卡&#34;或OpenCL&#34;在所有卡上工作&#34;解决这个任务。
对于c#,有一个很好的lib(对于OpenCL),名为cloo,易于使用