【问题标题】:compare between 2 Same-length byteArrays比较 2 个相同长度的 byteArrays
【发布时间】:2012-08-31 23:18:05
【问题描述】:

我在看@stackOverFlow 有两种方法,我想可能还有更多 在其他地方,我的问题是最好的性能是什么

第二个问题,我的代码只需要几个byte[]

     bool ArraysEqual(byte[] a1, byte[] a2)
     {
         if (a1 == a2)
             return true;
          if (a1 == null || a2 == null)
             return false;
          if (a1.Length != a2.Length)
             return false;
          for (int i = 0; i < a1.Length; i++)
         {
             if (a1[i] != a2[i])
                 return false;
         }
         return true;
     } 

我无法实现这个,我不知道我使用了错误的语法 所以如果我有一个辅助方法来读取一个字节 [] 文件

    public byte[] readByteArr(string FilePath)
    {
       return File.ReadAllBytes(FilePath);

    } 

i could make it simply via 



void CompareIt(){

byte[] src = readByteArr(S.bar);
byte[] dest = readByteArr(D.bar);
if(ArraysEqual(src, dest))
DoSomthing
}

我如何制作CompareIt(),在第二个代码中需要参数集我也尝试实现,只是为了检查哪个执行beeter

    bool ArraysEqual<T>(T[] a1, T[] a2)
    {
     if (ReferenceEquals(a1,a2))
         return true;
      if (a1 == null || a2 == null)
         return false;
      if (a1.Length != a2.Length)
         return false;
      EqualityComparer<T> comparer = EqualityComparer<T>.Default;
     for (int i = 0; i < a1.Length; i++)
     {
         if (!comparer.Equals(a1[i], a2[i]))
            return false;
     }
     return true;
 } 

实现最后一个的正确语法是什么,以及是否有更快的方法来比较两者

 byte[] 

知道 它们的长度相同。 您对此有何看法?

重新编辑:

首先是不安全的代码。

第二个是我写的第一个代码 (bool ArraysEqual())

第三个是

myArray.SequenceEqual(otherArray); 

现在好好看看这个 请允许我宣布,获胜者是:

[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int memcmp(byte[] b1, byte[] b2, long count);

static bool ByteArrayCompare(byte[] b1, byte[] b2)
{
    // Validate buffers are the same length.     
    // This also ensures that the count does not exceed the length of either buffer.
    return b1.Length == b2.Length && memcmp(b1, b2, b1.Length) == 0;
}

@混沌。 你能用我的 Pinvoke 发布 Your Ra​​ndom 的实现吗

【问题讨论】:

  • 我已更新我的答案以包含一些并行版本。当你有大的相等数组时,它们真的会发光。
  • 非常感谢,我希望再次在这些代码后面“见到”你@stackOverFlow,请关注我或其他...因为我还熟悉堆栈溢出功能,但我无法找到如何联系你。
  • 在我看来,我的“情况”总是更糟(:native is far with my capture images(toByte[]) 比较项目几乎 100% 的时间
  • 我重新编辑了最后一条评论:几乎 100% 的时间? 补充:在写完这篇评论一分钟后,我想到了你的:“取决于数据类型”,我们是否应该过滤arrayName.Length,看看我们首先要处理什么,然后画出正确的武器?那么我们是不是只是在黑暗中拍摄,有什么想法吗?我选错了参数还是不是最重要的参数还是唯一重要的参数?
  • 非常抱歉我的英语...没有时间重新检查拼写。

标签: c# performance bytearray


【解决方案1】:

如果您使用 .NET > 3.0:

myArray.SequenceEqual(otherArray);

MSDN - Enumerable.SequenceEqual

如果你想使用自定义的“EqualityComparer”,你可以使用MSDN - Enumerable.SequenceEqual with IEqualityComparer

;-)

【讨论】:

  • 我想……他在谈论字节数组比较,关于“文件内容读取”和通用数组比较……恕我直言,“SequenceEqual”方法将执行最好在每种情况下使用 1. 本机代码和 2. 正确的相等比较器....
  • 是短代码,所以我常用。但它几乎是比较两个数组最慢的方法。
  • 错误这个和 OP 的代码都是 O(n)。但这可能每个字节有 4 个接口调用,而 OP 最多有两个数组边界检查和一个简单的比较+分支。我 >90% 确定这比 OP 的第一个代码慢得多。甚至 OP 的代码也可能比不安全的实现慢得多。
  • @CodesInChaos - 我不得不同意这会更慢。我查看了 ILSpy 中的实现,在测试每个元素时大约有 3 个方法调用和 3 个属性访问。这还没有深入研究 IEnumeratorIEqualityComparer 实现。
  • 通过 stop wach 测试 1 次然后尝试 whileLoop 100 次,以有机会查看原始代码块 #1 和您的 SequenceEqual 之间是否存在差异,在 100K 回合中速度低于 10%,但 premeteve 获胜跨度>
【解决方案2】:
  • 最佳:数据是随机的
  • 最差:数据相等
  • 平均值:最好情况和最坏情况的平均值

真正的测试将包括数据几乎相等的情况,但我们在这里看到的平均值让我们很好地了解如果您的数据几乎可以是任何东西,这些事情将如何执行。最好的算法实际上取决于您期望什么样的数据。请注意,单线程安全方法在最好的情况下最快,但在最坏的情况下最慢。

class Program
{
    [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern int memcmp(byte[] b1, byte[] b2, long count);

    static bool AreEqualNative(byte[] a, byte[] b)
    {
        if (a == b)
            return true;
        if (a == null || b == null)
            return false;
        if (a.Length != b.Length)
            return false;
        return memcmp(a, b, a.Length) == 0;
    }

    static bool AreEqualSafe(byte[] a1, byte[] a2)
    {
        if (a1 == a2)
            return true;
        if (a1 == null || a2 == null)
            return false;
        if (a1.Length != a2.Length)
            return false;
        for (int i = 0; i < a1.Length; i++)
        {
            if (a1[i] != a2[i])
                return false;
        }
        return true;
    }

    static bool AreEqualSafeParallel(byte[] a1, byte[] a2, int start, int length)
    {
        for (int i = start; i < length; i++)
        {
            if (a1[i] != a2[i])
                return false;
        }
        return true;
    }

    static bool AreEqualSafeParallel(byte[] a, byte[] b)
    {
        if (a == b)
            return true;
        if (a == null || b == null)
            return false;
        if (a.Length != b.Length)
            return false;
        bool b1 = false;
        bool b2 = false;
        bool b3 = false;
        bool b4 = false;
        int quar = a.Length / 4;
        Parallel.Invoke(
            () => b1 = AreEqualSafeParallel(a, b, 0, quar),
            () => b2 = AreEqualSafeParallel(a, b, quar, quar),
            () => b3 = AreEqualSafeParallel(a, b, quar * 2, quar),
            () => b4 = AreEqualSafeParallel(a, b, quar * 3, a.Length)
        );
        return b1 && b2 && b3 && b4;
    }

    static unsafe bool AreEqualUnsafe(byte[] a, byte[] b)
    {
        if (a == b)
            return true;
        if (a == null || b == null)
            return false;
        if (a.Length != b.Length)
            return false;
        int len = a.Length / 8;
        if (len > 0)
        {
            fixed (byte* ap = &a[0])
            fixed (byte* bp = &b[0])
            {
                long* apl = (long*)ap;
                long* bpl = (long*)bp;

                for (int i = 0; i < len; i++)
                {
                    if (apl[i] != bpl[i])
                        return false;
                }
            }
        }
        int rem = a.Length % 8;
        if (rem > 0)
        {
            for (int i = a.Length - rem; i < a.Length; i++)
            {
                if (a[i] != b[i])
                    return false;
            }
        }
        return true;
    }

    static unsafe bool AreEqualUnsafeParallel(byte[] a, byte[] b, int start, int length)
    {
        int len = length / 8;
        if (len > 0)
        {
            fixed (byte* ap = &a[0])
            fixed (byte* bp = &b[0])
            {
                long* apl = (long*)ap;
                long* bpl = (long*)bp;

                for (int i = start; i < len; i++)
                {
                    if (apl[i] != bpl[i])
                        return false;
                }
            }
        }
        int rem = length % 8;
        if (rem > 0)
        {
            for (int i = length - rem; i < length; i++)
            {
                if (a[i] != b[i])
                    return false;
            }
        }
        return true;
    }

    static unsafe bool AreEqualUnsafeParallel(byte[] a, byte[] b)
    {
        if (a == b)
            return true;
        if (a == null || b == null)
            return false;
        if (a.Length != b.Length)
            return false;
        bool b1 = false;
        bool b2 = false;
        bool b3 = false;
        bool b4 = false;
        int quar = a.Length / 4;
        Parallel.Invoke(
            () => b1 = AreEqualUnsafeParallel(a, b, 0, quar),
            () => b2 = AreEqualUnsafeParallel(a, b, quar, quar),
            () => b3 = AreEqualUnsafeParallel(a, b, quar * 2, quar),
            () => b4 = AreEqualUnsafeParallel(a, b, quar * 3, a.Length)
        );
        return b1 && b2 && b3 && b4;
    }

    static readonly Random _rnd = new Random();
    static void SpeedTest(string name, int length, int iterations, Func<byte[], byte[], bool> func)
    {
        var a = new byte[length];
        var b = new byte[length];

        _rnd.NextBytes(a);
        _rnd.NextBytes(b);

        var sw1 = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            func(a, b);
        }
        sw1.Stop();

        var c = new byte[length];
        var d = new byte[length];

        var sw2 = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            func(c, d);
        }
        sw2.Stop();

        Console.WriteLine(name + ":");
        Console.WriteLine("  Best: " + sw1.Elapsed);
        Console.WriteLine("  Worst: " + sw2.Elapsed);
        Console.WriteLine("  Average: " + TimeSpan.FromTicks((sw1.Elapsed.Ticks + sw2.Elapsed.Ticks) / 2));
    }

    static void Test(bool shouldBeEqual, byte[] a, byte[] b)
    {
        if (shouldBeEqual != AreEqualSafe(a, b))
            throw new Exception();
        if (shouldBeEqual != AreEqualSafeParallel(a, b))
            throw new Exception();
        if (shouldBeEqual != AreEqualUnsafe(a, b))
            throw new Exception();
        if (shouldBeEqual != AreEqualUnsafeParallel(a, b))
            throw new Exception();
        if (shouldBeEqual != AreEqualNative(a, b))
            throw new Exception();
    }

    static void VerifyCorrectness()
    {
        Test(true,
        new byte[] { 1, 2, 3, 4, 5, 6, 7 },
        new byte[] { 1, 2, 3, 4, 5, 6, 7 });

        Test(true,
        new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
        new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

        Test(false,
        new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
        new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12 });
    }


    static void Main(string[] args)
    {
        VerifyCorrectness();

        var length = 1000000;
        var iterations = 10000;

        Console.WriteLine("Length:");
        Console.WriteLine("  " + length.ToString("N"));
        Console.WriteLine("Iterations:");
        Console.WriteLine("  " + iterations.ToString("N"));

        SpeedTest("Safe", length, iterations, AreEqualSafe);
        SpeedTest("SafeParallel", length, iterations, AreEqualSafeParallel);
        SpeedTest("Unsafe", length, iterations, AreEqualUnsafe);
        SpeedTest("UnsafeParallel", length, iterations, AreEqualUnsafeParallel);
        SpeedTest("Native", length, iterations, AreEqualNative);

        Console.ReadLine();
    }
}

【讨论】:

  • 使用更大的元素会使其更快,但会使最后几个字节的处理有点烦人。
  • @CodesInChaos ,我收到以下错误 错误 1 ​​不安全代码可能仅在使用 /unsafe 编译时出现
  • @LoneXcoder 您需要在项目选项中启用不安全代码。
  • @CodesInChaos - 我真的很惊讶我无法让它至少与随机分发的安全版本相提并论。如果您查看 IL,就会生成更多指令。如果没有不安全的演员阵容,那么在均匀分布上也会变慢。
  • @LoneXcoder - 只需检查项目属性的“构建”窗格。您会看到一个标有“允许不安全代码”的复选框。
猜你喜欢
  • 2010-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-02
  • 2021-02-25
  • 1970-01-01
相关资源
最近更新 更多