문제

나는 VB.net에서 긴 바닥을 비교하려고 노력하고 있으며 걸림돌에 빠졌습니다. 2 개의 50 메가 바이트 파일을 비교하는 데 거의 2 분이 걸리므로 분명히 뭔가 잘못하고 있습니다. 나는 메모리 톤의 X64 기계에 있으므로 문제가 없습니다. 현재 내가 사용하고있는 코드는 다음과 같습니다.

_Bytes 그리고 item.Bytes 비교할 두 개의 다른 배열이며 이미 같은 길이입니다.

For Each B In item.Bytes
   If B <> _Bytes(I) Then
        Mismatch = True
        Exit For
   End If
   I += 1
Next

잠재적으로 수백 메가 바이트, 심지어 기가 바이트 또는 두 개 정도의 가능한 파일을 가능한 빨리 비교할 수 있어야합니다. 더 빨리 할 수있는 제안이나 알고리즘이 있습니까?

Item.bytes 바이트 길이가 사용자가 추가하려는 항목과 일치하기 때문에 비교하기 위해 반환되는 데이터베이스/파일 시스템에서 가져온 객체입니다. 두 배열을 비교함으로써 사용자가 DB에 새로운 것을 추가했는지 확인할 수 있으며 그렇지 않으면 다른 파일에 매핑하고 하드 디스크 드라이브 공간을 낭비하지 않아도됩니다.

업데이트

배열을 Byte ()의 로컬 변수로 변환 한 다음 동일한 비교, 동일한 코드를 수행했으며 1 초 만에 실행되었습니다 (여전히 벤치마킹하고 다른 사람과 비교해야합니다). 변수와 일반 배열을 사용하면 크게 느려집니다. 왜 그런지 잘 모르겠지만 배열 사용에 대해 더 많은 질문을 제기합니다.

도움이 되었습니까?

해결책

이것은 _Bytes(I) 전화를? 매번 파일을로드하지 않습니까? 버퍼링을 사용하더라도 나쁜 소식이 될 것입니다!

많은 방법이있을 것입니다 미세 최적화 이것은 잠재적으로 안전하지 않은 코드 등을 사용하는 한 번에 오랫동안보고하는 측면에서 합리적인 먼저 성능. 분명히 매우 이상한 일이 있습니다.

비교 코드를 두 개의 바이트 배열을 취하는 별도의 함수로 추출하는 것이 좋습니다. 그렇게하면 당신이 이상한 일을하지 않을 것임을 알고 있습니다. 나는 또한 간단한 것을 사용합니다 For 루프보다는 For Each 이 경우 - 더 간단합니다. 아, 그리고 길이가 먼저 올바른지 확인하십시오 :)

편집 : 여기에 사용할 코드 (테스트되지 않았지만 간단함)가 있습니다. 순간 C#에 있습니다.

public static bool Equals(byte[] first, byte[] second)
{
    if (first == second)
    {
        return true;
    }
    if (first == null || second == null)
    {
        return false;
    }
    if (first.Length != second.Length)
    {
        return false;
    }
    for (int i=0; i < first.Length; i++)
    {
        if (first[i] != second[i])                
        {
            return false;
        }
    }
    return true;
}

편집 : 그리고 여기 VB는 다음과 같습니다.

Public Shared Function ArraysEqual(ByVal first As Byte(), _
                                   ByVal second As Byte()) As Boolean
    If (first Is second) Then
        Return True
    End If

    If (first Is Nothing OrElse second Is Nothing) Then
        Return False
    End If
    If  (first.Length <> second.Length) Then
         Return False
    End If

    For i as Integer = 0 To first.Length - 1
        If (first(i) <> second(i)) Then
            Return False
        End If
    Next i
    Return True
End Function

다른 팁

동일한 크기의 두 바이트 배열을 비교하는 가장 빠른 방법은 Interop을 사용하는 것입니다. 콘솔 애플리케이션에서 다음 코드를 실행하십시오.

using System;
using System.Runtime.InteropServices;
using System.Security;

namespace CompareByteArray
{
    class Program
    {
        static void Main(string[] args)
        {
            const int SIZE = 100000;
            const int TEST_COUNT = 100;

            byte[] arrayA = new byte[SIZE];
            byte[] arrayB = new byte[SIZE];

            for (int i = 0; i < SIZE; i++)
            {
                arrayA[i] = 0x22;
                arrayB[i] = 0x22;
            }

            {
                DateTime before = DateTime.Now;
                for (int i = 0; i < TEST_COUNT; i++)
                {
                    int result = MemCmp_Safe(arrayA, arrayB, (UIntPtr)SIZE);

                    if (result != 0) throw new Exception();
                }
                DateTime after = DateTime.Now;

                Console.WriteLine("MemCmp_Safe: {0}", after - before);
            }

            {
                DateTime before = DateTime.Now;
                for (int i = 0; i < TEST_COUNT; i++)
                {
                    int result = MemCmp_Unsafe(arrayA, arrayB, (UIntPtr)SIZE);

                    if (result != 0) throw new Exception();
                }
                DateTime after = DateTime.Now;

                Console.WriteLine("MemCmp_Unsafe: {0}", after - before);
            }


            {
                DateTime before = DateTime.Now;
                for (int i = 0; i < TEST_COUNT; i++)
                {
                    int result = MemCmp_Pure(arrayA, arrayB, SIZE);

                    if (result != 0) throw new Exception();
                }
                DateTime after = DateTime.Now;

                Console.WriteLine("MemCmp_Pure: {0}", after - before);
            }
            return;
        }

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint="memcmp", ExactSpelling=true)]
        [SuppressUnmanagedCodeSecurity]
        static extern int memcmp_1(byte[] b1, byte[] b2, UIntPtr count);

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "memcmp", ExactSpelling = true)]
        [SuppressUnmanagedCodeSecurity]
        static extern unsafe int memcmp_2(byte* b1, byte* b2, UIntPtr count);

        public static int MemCmp_Safe(byte[] a, byte[] b, UIntPtr count)
        {
            return memcmp_1(a, b, count);
        }

        public unsafe static int MemCmp_Unsafe(byte[] a, byte[] b, UIntPtr count)
        {
            fixed(byte* p_a = a)
            {
                fixed (byte* p_b = b)
                {
                    return memcmp_2(p_a, p_b, count);
                }
            }
        }

        public static int MemCmp_Pure(byte[] a, byte[] b, int count)
        {
            int result = 0;
            for (int i = 0; i < count && result == 0; i += 1)
            {
                result = a[0] - b[0];
            }

            return result;
        }

    }
}

바이트를 알 필요가 없다면 한 번에 8 개를 제공하는 64 비트 int를 사용하십시오. 실제로 8 세트로 격리 한 후 잘못된 바이트를 알아낼 수 있습니다.

사용 BinaryReader:

saveTime  = binReader.ReadInt32()

또는 INT 배열의 경우 :

Dim count As Integer = binReader.Read(testArray, 0, 3)

더 나은 접근 방식 ... 두 사람이 다른지 확인하려고한다면 전체 바이트 배열을 거치지 않고 각 바이트 배열의 해시를 문자열로 생성하고 문자열을 비교하여 시간을 절약하십시오. MD5는 잘 작동하고 매우 효율적입니다.

도움이 될 수있는 두 가지가 있습니다.

첫째, 두 번째 배열에 항상 item.cytes에 액세스하는 대신 로컬 변수를 사용하여 배열을 직접 가리 킵니다. 즉, 루프를 시작하기 전에 다음과 같은 작업을 수행하십시오.

 array2 = item.Bytes

이렇게하면 바이트를 원할 때마다 객체에서 탈환의 오버 헤드가 절약됩니다. 특히 해당 속성에 게터 방법이있는 경우 Visual Basic에서는 비쌀 수 있습니다.

또한 "각각"대신 "명확한 루프"를 사용하십시오. 이미 배열의 길이를 알고 있으므로 해당 값을 사용하여 루프를 코딩하십시오. 이것은 배열을 컬렉션으로 취급하는 오버 헤드를 피할 수 있습니다. 루프는 다음과 같이 보입니다.

For i = 1 to max Step 1
   If (array1(i) <> array2(i)) 
       Exit For
   EndIf 
Next

비교 알고리즘과 엄격하게 관련이 없습니다.

병목 현상이 사용 가능한 메모리 및 바이트 어레이를로드하는 데 사용되는 시간과 관련이 없다고 확신합니까? 2GB 바이트 배열 2 개를로드하여 비교하면 대부분의 기계를 무릎에 가져올 수 있습니다. 프로그램 설계에서 허용되면 스트림을 사용하여 작은 청크를 대신 읽으십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top