簡體   English   中英

檢查字節數組是否只包含1個值的最快方法

[英]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))

那么這是最快的方式還是有更好的方法來做到這一點?

肯定有更快的方法來優化您正在執行的特定檢查。 一些評論已經表明的真正問題是它是否真的有必要? 是否值得優化查詢真的取決於幾個問題,你必須首先問自己。

  1. 你的表現標准是什么?

    您應該每秒處理多少個陣列? 如果答案是1000或更少,那么我肯定不會打擾嘗試優化代碼。 如果答案是每秒數百萬個數組,那么您可能需要考慮對代碼進行一些性能測試。

  2. 您期望什么類型的數據?

    如果您處理的99%的緩沖區有效(並非所有0xFF字節),那么在大多數情況下,您的循環很可能在前幾次檢查中存在。 如果僅適用於1%的工作負載,那么針對最壞情況優化算法是否有意義。

  3. 通過更改比較方法,我會對您的代碼引入哪些風險,其好處是否大於風險?

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM