当条件为False时执行语句True Block [英] If Statement True Block Executed When Condition is False

查看:86
本文介绍了当条件为False时执行语句True Block的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我优化了扩展方法来比较两个流的相等性(逐字节)-知道这是一种热门方法,因此我尝试对其进行尽可能的优化(这些流可以达到几兆字节的长度).我基本上想出了以下方法:

I optimized an extension method to compare two streams for equality (byte-for-byte) - knowing that this is a hot method I tried to optimize it as far as possible (the streams can reach into multi-megabyte lengths). I essentially came up with the following approach:

[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块(返回false).我逐一检查了每个项目,然后检查了不等于"的结果. 我完全难以置信:

The problem is that the convert1.UInt64[i] != convert2.UInt64[i] if block (returning false) is being evaluated even when the values are the equal. I checked each on individually, then checked the outcome of the 'not equals'. I am in pure disbelief:

我还没有弄错指令指针-这是执行代码和监视销有效的方式.

I have not messed with the instruction pointer - this is how the code executed and the watch pin is live.

有什么想法会发生这种情况吗?

Any ideas how this could happen?

推荐答案

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

通常,调试器很难与这个联合体配合使用,当我尝试它时,它无法显示数组内容.但是,核心问题无疑是for()结束表达式中的+1.当 len 被8整除时,它将索引数组到其最后一个元素之外.运行时无法捕获此错误,数组重叠会导致Length属性具有虚假值.接下来发生的是未定义的行为,您正在读取不属于数组的字节.一种解决方法是将数组增加7个字节.

The debugger in general has a hard time with this union, it can't display the array content when I try it. But the core problem is no doubt the +1 in the for() end expression. That indexes the array beyond its last element when len is divisible by 8. The runtime cannot catch this mistake, overlapping the arrays causes the Length property to have a bogus value. What happens next is undefined behavior, you are reading bytes that are not part of the array. A workaround is to make the array 7 bytes longer.

这种代码并非完全是一种优化,在32位计算机上读取和比较uint64的成本很高,尤其是在数组未正确对齐的情况下.这种可能性大约为50%.一个更好的捕鼠器是使用Windows运行时可用的C运行时memcmp()函数:

This kind of code is not exactly an optimization, reading and comparing uint64 on a 32-bit machine is expensive, especially when the array isn't aligned correctly.. About 50% odds for that. A better mousetrap is to use the C runtime memcmp() function, available on any Windows machine:

    [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;

将此性能与比较字节的普通for()循环进行比较.最终的限制是内存总线带宽.

Do compare the perf of this with a plain for() loop that compares bytes. The ultimate throttle here is the memory bus bandwidth.

这篇关于当条件为False时执行语句True Block的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆