簡體   English   中英

如果條件為假則執行語句True Block

[英]If Statement True Block Executed When Condition is False

我優化了一個擴展方法來比較兩個流的相等性(逐字節) - 知道這是一個熱門的方法,我試圖盡可能地優化它(流可以達到數兆字節的長度)。 我基本上想出了以下方法:

[StructLayout(LayoutKind.Explicit)]
struct Converter
{
    [FieldOffset(0)]
    public Byte[] Byte;

    [FieldOffset(0)]
    public UInt64[] UInt64;
}

/// <summary>
/// Compares two streams for byte-by-byte equality.
/// </summary>
/// <param name="target">The target stream.</param>
/// <param name="compareTo">The stream to compare the target to.</param>
/// <returns>A value indicating whether the two streams are identical.</returns>
public static bool CompareBytes(this Stream target, Stream compareTo)
{
    if (target == null && compareTo == null)
        return true;
    if (target == null || compareTo == null)
        return false;
    if (target.Length != compareTo.Length)
        return false;
    if (object.ReferenceEquals(target, compareTo))
        return true;
    if (!target.CanRead || !target.CanSeek)
        throw new ArgumentOutOfRangeException("target");
    if (!compareTo.CanRead || !compareTo.CanSeek)
        throw new ArgumentOutOfRangeException("target");
    lock (target)
    {
        lock (compareTo)
        {
            var origa = target.Position;
            var origb = compareTo.Position;
            try
            {
                target.Position = compareTo.Position = 0;

                // Shrink the number of comparisons.
                var arr1 = new byte[4096];
                var convert1 = new Converter() { Byte = arr1 };
                var arr2 = new byte[4096];
                var convert2 = new Converter() { Byte = arr2 };

                int len;
                while ((len = target.Read(arr1, 0, 4096)) != 0)
                {
                    if (compareTo.Read(arr2, 0, 4096) != len)
                        return false;
                    for (var i = 0; i < (len / 8) + 1; i++)
                        if (convert1.UInt64[i] != convert2.UInt64[i])
                            return false;
                }

                return true;
            }
            finally
            {
                target.Position = origa;
                compareTo.Position = origb;
            }
        }
    }
}

問題是即使值相等,也會評估convert1.UInt64[i] != convert2.UInt64[i] if block(返回false )。 我單獨檢查每個,然后檢查'不等於'的結果。 我完全不相信

價值觀不相等

我沒有搞亂指令指針 - 這是執行代碼和監視引腳的實時方式。

任何想法如何發生這種情況?

  for (var i = 0; i < (len / 8) + 1; i++)

調試器通常很難用這個聯合,它在我嘗試時無法顯示數組內容。 但核心問題無疑是for()結束表達式中的+1。 len可被8整除時,將數組索引到其最后一個元素之外。運行時無法捕獲此錯誤,重疊數組會導致Length屬性具有偽值。 接下來發生的是未定義的行為,您正在讀取不屬於該數組的字節。 解決方法是使數組長7個字節。

這種代碼並不完全是一種優化,在32位機器上讀取和比較uint64是很昂貴的,特別是當陣列沒有正確對齊時。大約50%的可能性。 更好的捕鼠器是使用任何Windows機器上可用的C運行時memcmp()函數:

    [DllImport("msvcrt.dll")]
    private static extern int memcmp(byte[] arr1, byte[] arr2, int cnt);

並像這樣使用它:

    int len;
    while ((len = target.Read(arr1, 0, 4096)) != 0) {
        if (compareTo.Read(arr2, 0, 4096) != len) return false;
        if (memcmp(arr1, arr2, len) != 0) return false;
    }
    return true;

比較它的perf與用於比較字節的plain for()循環。 這里的最終節流是內存總線帶寬。

這樣的問題通常是理解優化如何工作的問題。 這行代碼很可能正在被執行,因為返回的錯誤子句被合並到較低級別的一組指令中。 造成這種問題的其他原因是,如果您所使用的體系結構允許條件執行,其中某些指令在調試器中被命中,但結果永遠不會提交給體系結構級別的寄存器。

首先驗證代碼是否在調試模式下工作。 然后,當您確信結果與發布模式相同時,請查看基礎指令以確定手頭的編譯器優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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