[英]What is the fastest way to find if an array of byte arrays contains another byte array?
[英]Fastest way to check if a byte array contains only 1 value
Oke現在顯然我可以檢查字節數組是否只包含1個值,但我不知道這是否是最快的方法。 問題是有時我會得到一個只有FF(255)值的字節數組,如果發生這種情況我需要在接下來的代碼中忽略它,所以我做的事情如下:
var onlyFF = true;
foreach(var value in programCode)
{
if (value != 0xFF)
{
onlyFF = false;
break;
}
}
但這是最快的方式嗎? 我將不得不檢查大量的數組(雖然所有數組都很小(350))
那么這是最快的方式還是有更好的方法來做到這一點?
肯定有更快的方法來優化您正在執行的特定檢查。 一些評論已經表明的真正問題是它是否真的有必要? 是否值得優化查詢真的取決於幾個問題,你必須首先問自己。
你的表現標准是什么?
您應該每秒處理多少個陣列? 如果答案是1000或更少,那么我肯定不會打擾嘗試優化代碼。 如果答案是每秒數百萬個數組,那么您可能需要考慮對代碼進行一些性能測試。
您期望什么類型的數據?
如果您處理的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%的緩沖區無效,則獲得最大的性能提升。 這讓我們回到最初的問題是優化代碼真的值得嗎?
一個相當簡單的方法是更快地獲得一個ulong*
到數組並一次比較8字節塊與0xFFFFFFFFFFFFFFFFUL
。 您可能需要通過在那里按字節比較來處理數組開始和結束時的錯位。
然后,您可以將循環展開4次以將循環開銷減少到幾乎為零。 要比這更快地完成它將很難(但可能)。
另一個相當簡單的選擇是在C和PInvoke中編寫它。 C編譯器有很復雜的方法來實現這一點。 .NET JIT沒有。 雖然我很驚訝GCC和LLVM在這里都沒有做任何特別的伎倆 。
使用不同的代碼模式LLVM提供以下優化:
if (array[i + 0] & array[i + 1] & array[i + 2] & array[i + 3] == 0xFF)
return true;
這節省了很多指令和分支。
對我來說,這聽起來像一個可並行化的問題。 如果你有數百個這樣的陣列,里面有幾百個字節,我會考慮使用GPU
您可以使用CUDA“僅在Nvidia卡上工作”或OpenCL“在所有卡上工作”來解決此任務。
對於c#,有一個很好的lib(對於OpenCL)叫做cloo,它很容易使用
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.