Warum klappt Binary bei mir nicht



  • @hkdd sagte in Warum klappt Binary bei mir nicht:

    @hustbaer
    mit meiner Delphi-Aussage muss ich mich revidieren. Die Puffer-Größe hat doch eine entscheidende Auswirkung.
    Hier ein paar meiner Mess-Ergebnisse.

    Puffergröße     Laufzeit in 
      hex            Min:Sek
    0x010000           2:04
    0x020000           1:14  <= 128 * 1024
    0x030000           1:00
    0x040000           0:56
    0x050000           0:51
    0x060000           0:47
    0x070000           0:43
    0x080000           0:41
    0x090000           0:44
    0x0A0000           0:43
    0x0B0000           0:40
    0x0C0000           0:42
    0x0D0000           0:40
    0x0E0000           0:40
    0x0F0000           0:40
    0x100000           0:37
    0x110000           0:39
    0x120000           0:38
    0x130000           0:41
    0x140000           0:37
    0x150000           0:37
    0x160000           0:38
    0x170000           0:28
    0x180000           0:25 = 1536 * 1024
    0x200000           0:38
    0x280000           0:35
    0x300000           0:33
    

    Ich habe mich jetzt für 0x180000 Bytes entschieden.
    Das ist gut in Delphi und in C#.

    Evtl. hängt das aber auch von der Hardware ab (CPU, RAM, GDD, SSD, m.2 u.a.m.).

    Ja, vermutlich. Was auch mit reinspielt ist ob du zwei Verzeichnisse auf dem selben Datenträger vergleichst oder zwei Verzeichnisse auf verschiedenen Datenträgern. Speziell wenn beide Verzeichnisse auf der selben HDD steht werden sehr grosse Puffer vermutlich viel bringen. Wenn es dagegen verschiedene Datenträger sind oder die Daten von einer SSD kommen sollte eine Puffergrösse zwischen 64k und 1 MB ausreichend sein.

    @hustbaer sagte in Warum klappt Binary bei mir nicht:

    Mit dem Asynchronen Vergleich wird es vermutlich nichts bringen. Wenn du synchron vergleichst u.U. schon.

    Was meinst Du damit ?
    Ich lese Datei1 in Puffer1 und Datei2 in Puffer , danach Vergleich Puffer 1 mit 2, und danach wieder Datei1 in Puffer1 usw.

    Mit FileOptions.SequentialScan teilst du dem OS mit dass du vor hast die Datei linear zu lesen. Das OS sollte dann dafür sorgen dass die nächsten Stücke der Datei bereits im Hintergrund gelesen werden, bevor dein Programm sie anfordert ("read ahead"). Wenn du wie in der von mir veränderten Version den Vergleich asynchron in einem eigenen Thread machst, dann wird das nicht viel bringen. Weil ja der Haupt-Thread sofort das nächste Datenstück anfordert. Wenn du dagegen den Vergleich im selben Thread machst wie das Lesen kann das viel bringen. Weil das OS dann eben während dein Programm den Vergleich ausführt bereits das nächste Datenstück von der HDD/SSD anfordert.

    Allerdings sollte das OS auch schlau genug sein zu erkennen dass du die Datei linear liest, ohne dass du FileOptions.SequentialScan verwendest. Das kann aber wiederrum abhängig von der Puffergrösse sein. Auf Linux z.B. bekommst du AFAIK read-ahead per Default nur mit Puffergrössen bis max. 128 kB.



  • Wenn die Verzeichnisse auf unterschiedlichen Datenträgern liegen könnte folgende Änderung nochmal einiges bringen:

    		using (var fs1 = new FileStream(pDsn1, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
    		using (var fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
    		{
    				// ...
    				// ...
    				p.Length = (int)LeseLen;
    				var r1 = fs1.ReadAsync(p.Buffer1, 0, (int)LeseLen);
    				fs2.Read(p.Buffer2, 0, (int)LeseLen);
    				r1.Wait();
    
    				if (MitComp)
    				// ...
    

    Mit kleinen Puffern macht das die Sache bei mir langsamer, aber mit ~1MB Puffern bringt es bei mir nochmal ne deutliche Beschleunigung.



  • Jetzt müsste man nur noch eine Funktion finden, welche automatisch für die lokale Gegebenheit die beste Puffergröße ermittelt.



  • @hustbaer sagte in Warum klappt Binary bei mir nicht:

    using (var fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))

    Wenn ich diese Parameter hinzufüge ( 4 und 5)

      FileStream fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, 4096, FileOptions.SequentialScan);
    

    dann wird für (4) = 4096 angezeigt: CS1503: Konvertierung von int in System.IO.FileShare nicht möglich.
    und für (5) = FileOptions.SequentialScan wird angezeigt:
    CS1503: Konvertierung von System.IO.FileOptions in int nicht möglich.

    Mit ALT+Eingabe wird das Statement folgendermaßen korrigiert

    FileStream fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, (FileShare)4096, (int)FileOptions.SequentialScan);
    

    Beim Ausführen erhalte ich allerdings einen Fehler:
    System.ArgumentOutOfRangeException: "Der Enumerationswert lag außerhalb des gültigen Bereichs. Parametername: share"

    Ich benutze allerdings kein USING.



  • @hkdd
    Du hast FileShare.Read unterschlagen.



  • @hustbaer
    JA, das war es - trotz meiner neuen Linsen in den Augen habe ich das übersehen.
    Was bedeuten diese 4096, ist das der Lesepuffer oder nimmt Read dann die angegebene Anzahl Bytes zum lesen ?



  • @hkdd

    Was bedeuten diese 4096, ist das der Lesepuffer oder nimmt Read dann die angegebene Anzahl Bytes zum lesen ?

    Das ist die Grösse für den internen Puffer der File-Streams. Wenn kleinere Lese bzw. Schreib-Operationen gemacht werden, dann gehen die über den Puffer. Oft liest bzw. schreibt man Dateien ja in kleinen Stücken, da bringt das dann einiges.

    Lese bzw. Schreib-Operationen die grösser als der interne Puffer sind werden allerdings direkt an die OS Funktionen weitergeleitet. Für dein Programm ist der Puffer also irrelevant. Alle Konstruktoren wo man FileOptions angeben kann erfordern allerdings dass man die Puffergrösse angibt. Also hab ich einfach den Default-Wert von 4096 genommen.



  • @hkdd sagte in Warum klappt Binary bei mir nicht:

    Ich benutze allerdings kein USING.

    Macht in dem Fall keinen Unterschied. Bloss: wieso verwendest du es nicht?



  • @hustbaer
    Ein wenig schneller scheint es zu sein. Das erste Ergebnis ist von gestern und das zweite von heute

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        82 Unterordner gefunden
        2.446 Dateien     gefunden
    	- davon 2.446 identische Dateien verglichen.
        Es wurden 208.144.569.612 Bytes = 203.266.181 K-Bytes verglichen.
        133.902 Puffer gelesen, Pufferlänge: 1.572.864 Bytes.
        Start 19:24:40  Ende 19:50:57  Dauer 00:26:17.5
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompCs - Dateien vergleichen - (C) 12.12.2022 Hartmut aus Dresden
    ---------------------------------------------------------------
    Parameter: N:\VideosN  N:\VideosN  
    ---------------------------------------------------------------
    Vergleich: N:\VideosN\
          mit: N:\VideosN\
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        82 Unterordner gefunden
        2.446 Dateien     gefunden
    	- davon 2.446 identische Dateien verglichen.
        Es wurden 208.144.569.612 Bytes = 203.266.181 K-Bytes verglichen.
        133.902 Puffer gelesen, Pufferlänge: 1.572.864 Bytes.
        Start 16:08:58  Ende 16:34:20  Dauer 00:25:22.0
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    Ich habe versucht bei den beiden FileStream Anweisungen USING davor zu schreiben und nach dem zweiten Using den Rest mit {...} einzuklammern - das klappt aber nicht. Ohne USING - alles ist OK.

            //=================================================
            // Datei 1 und 2 lesen und vergleichen
            //=================================================
            private bool VergleicheDateien(string pDsn1, string pDsn2, Int64 lenFile, string pPfad)
            {
                bool rc;
                Int64 RestLen = lenFile; // Dateilänge beider Dateien
                Int64 LeseLen = Math.Min(RestLen, MaxPuffL);
    
                FileStream fs1 = new FileStream(pDsn1, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan);
                FileStream fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan);
    
                while (LeseLen > 0)
                {
                    Application.DoEvents();
                    if (Abbruch > 0) { return false; }
    
                    GesBytes += LeseLen; // Anzahl gelesene Bytes gesamt
    
                    this.Text = "CompHk " + GesBytes.ToString("###,###,###,###,##0") + " Bytes " + pPfad;
    
                    fs1.Read(ByPu1, 0, (int)LeseLen);
                    fs2.Read(ByPu2, 0, (int)LeseLen);
    
                    AnzPuff++;                 // Anzahl verglichene Puffer
    
                    if (LeseLen < 9)
                    {
                        for (int b = 0; b < LeseLen; b++)
                        {
                            if (ByPu1[b] != ByPu2[b])
                            {
                                goto VerglErr;     // Vergleich abbrechen
                            }
                        }
                        break;
                    }
    
                    switch (VergleichsMethode) // Welche Art des Vergleiches
                    {
                        case compSequenceEqual: // C# interne Funktion
                            if (!(ByPu1.Take((int)LeseLen).SequenceEqual(ByPu2.Take((int)LeseLen))))
                            {
                                goto VerglErr;     // Vergleich abbrechen
                            }
                            break;
                        case compMemCmp: // [DllImport]  msvcrt.dll
                            if (memcmp(ByPu1, ByPu2, LeseLen) != 0)
                            {
                                goto VerglErr;     // Vergleich abbrechen
                            }
                            break;
                        case compForNxt: // C# interner Byte-für-Byte-Vergleich
                            for (int b = 0; b < LeseLen; b++)
                            {
                                if (ByPu1[b] != ByPu2[b])
                                {
                                    goto VerglErr;     // Vergleich abbrechen
                                }
                            }
                            break;
                        case compUnsafe: // unsafe MemCmp
                            if (!MemCmp(ByPu1, ByPu2, (int)LeseLen))
                            {
                                goto VerglErr;     // Vergleich abbrechen
                            }
                            break;
                        case compRtlCompareMemory: // [DllImport] kernel32.dll RtlCompareMemory
    
                            IntPtr len = (IntPtr)LeseLen;
                            //IntPtr rc = RtlCompareMemory(ByPu1, ByPu2, len);
                            var rCod = RtlCompareMemory(ByPu1, ByPu2, len);
    
                            if (rCod != len)
                            {
                                goto VerglErr;     // Vergleich abbrechen
                            }
                            break;
                        case compCompareByteArray: // [DllImport] CompareByteArray.dll von HK
                            if (CompareByteArray(ByPu1, ByPu2, (int)LeseLen) != 0)
                            {
                                goto VerglErr;     // Vergleich abbrechen
                            }
                            break;
                    } // switch (VergleichsMethode)
    
                    RestLen -= LeseLen;
                    LeseLen = Math.Min(RestLen, MaxPuffL);
    
                } //   while (LeseLen > 0)
            
    
            AnzFilesOK++;
                rc = true;
                goto UpEnde;     // Vergleich abbrechen
    
            VerglErr:
                ByteDiff++; // es gibt Differenzen
                rc = false;
    
            UpEnde:
                fs1.Close();
                fs2.Close();
    
                return rc;
    
            } // static bool VergleicheDateien(string pDsn1, string pDsn2, Int64 lenFile)
    


  • @hkdd
    Hab's nicht ausprobiert, aber ich nehme an der Grund für die Fehler ist dass du gotos verwendest. Ich würde empfehlen auf goto zu verzichten. Weiters wäre es praktisch die eigentliche Vergleichs-Funktion vom Rest des Programms zu entkoppeln. z.B. von der Aktualisierung des User-Interface und dem Test ob abgebrochen werden soll. Könnte dann z.B. so aussehen:

            private bool VergleicheDateien(string pDsn1, string pDsn2, Int64 lenFile, string pPfad)
            {
                int res = VergleicheDateien0(pDsn1, pDsn2, lenFile, leseLen =>
                {
                    Application.DoEvents();
                    if (Abbruch > 0) { return false; }
    
                    GesBytes += leseLen; // Anzahl gelesene Bytes gesamt
                    AnzPuff++;           // Anzahl verglichene Puffer
    
                    this.Text = "CompHk " + GesBytes.ToString("###,###,###,###,##0") + " Bytes " + pPfad;
                    return true;
                });
    
                switch (res)
                {
                    case 0:
                        ByteDiff++;
                        return false;
                    case 1:
                        AnzFilesOK++;
                        return true;
                    default:
                        return false;
                }
            }
    
            private int VergleicheDateien0(string pDsn1, string pDsn2, Int64 lenFile, Func<long, bool> fortschrittsCallback)
            {
                Int64 RestLen = lenFile; // Dateilänge beider Dateien
                Int64 LeseLen = Math.Min(RestLen, MaxPuffL);
    
                using (FileStream fs1 = new FileStream(pDsn1, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
                using (FileStream fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
                {
                    while (LeseLen > 0)
                    {
                        if (!fortschrittsCallback(LeseLen)) { return -1; }
    
                        fs1.Read(ByPu1, 0, (int)LeseLen);
                        fs2.Read(ByPu2, 0, (int)LeseLen);
    
                        if (LeseLen < 9)
                        {
                            for (int b = 0; b < LeseLen; b++)
                            {
                                if (ByPu1[b] != ByPu2[b])
                                {
                                    return 0;
                                }
                            }
                            break;
                        }
    
                        switch (VergleichsMethode) // Welche Art des Vergleiches
                        {
                            case compSequenceEqual: // C# interne Funktion
                                if (!(ByPu1.Take((int)LeseLen).SequenceEqual(ByPu2.Take((int)LeseLen))))
                                {
                                    return 0;
                                }
                                break;
                            case compMemCmp: // [DllImport]  msvcrt.dll
                                if (memcmp(ByPu1, ByPu2, LeseLen) != 0)
                                {
                                    return 0;
                                }
                                break;
                            case compForNxt: // C# interner Byte-für-Byte-Vergleich
                                for (int b = 0; b < LeseLen; b++)
                                {
                                    if (ByPu1[b] != ByPu2[b])
                                    {
                                        return 0;
                                    }
                                }
                                break;
                            case compUnsafe: // unsafe MemCmp
                                if (!MemCmp(ByPu1, ByPu2, (int)LeseLen))
                                {
                                    return 0;
                                }
                                break;
                            case compRtlCompareMemory: // [DllImport] kernel32.dll RtlCompareMemory
    
                                IntPtr len = (IntPtr)LeseLen;
                                //IntPtr rc = RtlCompareMemory(ByPu1, ByPu2, len);
                                var rCod = RtlCompareMemory(ByPu1, ByPu2, len);
    
                                if (rCod != len)
                                {
                                    return 0;
                                }
                                break;
                            case compCompareByteArray: // [DllImport] CompareByteArray.dll von HK
                                if (CompareByteArray(ByPu1, ByPu2, (int)LeseLen) != 0)
                                {
                                    return 0;
                                }
                                break;
                        } // switch (VergleichsMethode)
    
                        RestLen -= LeseLen;
                        LeseLen = Math.Min(RestLen, MaxPuffL);
    
                    } //   while (LeseLen > 0)
    
                    return 1;
                }
            }
    

    Die neue Funktion VergleicheDateien0 ist jetzt völlig unabhängig vom User-Interface. Was viele Vorteile hat, z.B. dass man sie dadurch unabhängig vom User-Interface testen kann.



  • ps:
    Hast du ReadAsync auch mal ausprobiert?

    			var r1 = fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    			fs2.Read(ByPu2, 0, (int)LeseLen);
    			r1.Wait();
    


  • @hustbaer
    leider bin ich kein so ausgefuchster Programmierer, wie Du, aber ich kann viel von Dir lernen - DANKE dafür und auch an all die anderen hier im Forum.
    Ich habe jetzt erst einmal die USINGs eingebaut und die GOTOs entfernt. Braucht man bei USING keine CLOSE mehr ?
    ReadAsync werde ich nun auch noch ausprobieren, ob damit noch ein paar Sekunden herauszuholen sind.

            //=================================================
            // Datei 1 und 2 lesen und vergleichen
            //=================================================
            private bool VergleicheDateien(string pDsn1, string pDsn2, Int64 lenFile, string pPfad)
            {
                bool rc = true;
                Int64 RestLen = lenFile; // Dateilänge beider Dateien
                Int64 LeseLen = Math.Min(RestLen, MaxPuffL);
    
                using (FileStream fs1 = new FileStream(pDsn1, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
                using (FileStream fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
                {
                    while (LeseLen > 0 && rc)
                    {
                        Application.DoEvents();
                        if (Abbruch > 0) { return false; }
    
                        GesBytes += LeseLen; // Anzahl gelesene Bytes gesamt
    
                        this.Text = "CompHk " + GesBytes.ToString("###,###,###,###,##0") + " Bytes " + pPfad;
    
                        fs1.Read(ByPu1, 0, (int)LeseLen);
                        fs2.Read(ByPu2, 0, (int)LeseLen);
    
                        AnzPuff++;                 // Anzahl verglichene Puffer
    
                        if (LeseLen < 9)
                        {
                            for (int b = 0; b < LeseLen; b++)
                            {
                                if (ByPu1[b] != ByPu2[b])
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                            }
                            break;
                        }
    
                        switch (VergleichsMethode) // Welche Art des Vergleiches
                        {
                            case compSequenceEqual: // C# interne Funktion
                                if (!(ByPu1.Take((int)LeseLen).SequenceEqual(ByPu2.Take((int)LeseLen))))
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compMemCmp: // [DllImport]  msvcrt.dll
                                if (memcmp(ByPu1, ByPu2, LeseLen) != 0)
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compForNxt: // C# interner Byte-für-Byte-Vergleich
                                for (int b = 0; b < LeseLen; b++)
                                {
                                    if (ByPu1[b] != ByPu2[b])
                                    {
                                        rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                    }
                                }
                                break;
                            case compUnsafe: // unsafe MemCmp
                                if (!MemCmp(ByPu1, ByPu2, (int)LeseLen))
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compRtlCompareMemory: // [DllImport] kernel32.dll RtlCompareMemory
    
                                IntPtr len = (IntPtr)LeseLen;
                                //IntPtr rc = RtlCompareMemory(ByPu1, ByPu2, len);
                                var rCod = RtlCompareMemory(ByPu1, ByPu2, len);
    
                                if (rCod != len)
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compCompareByteArray: // [DllImport] CompareByteArray.dll von HK
                                if (CompareByteArray(ByPu1, ByPu2, (int)LeseLen) != 0)
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                        } // switch (VergleichsMethode)
    
                        RestLen -= LeseLen;
                        LeseLen = Math.Min(RestLen, MaxPuffL);
    
                    } //   while (LeseLen > 0 && rc)
                }
    
    
                if (rc) { AnzFilesOK++; } // es gibt keine Differenzen
                else    { ByteDiff++; }   // es gibt Differenzen
    
              //fs1.Close();
              //fs2.Close();
    
                return rc;
    
            } // static bool VergleicheDateien(string pDsn1, string pDsn2, Int64 lenFile)
    


  • @hustbaer sagte in Warum klappt Binary bei mir nicht:

    var r1 = fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    fs2.Read(ByPu2, 0, (int)LeseLen);
    r1.Wait();

    var r1 = fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    

    r1 ist m.E. doch die zurück gegebene tatsächlich gelesene Länge, also ein int-Wert.
    Macht r1.Wait() dann einen Sinn ?

    In den gefundenen ReadAsync Beispielen sieht es etwa so aus

    var r1ReadLen = await fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    


  • @hkdd sagte in Warum klappt Binary bei mir nicht:

    Braucht man bei USING keine CLOSE mehr ?

    Nein braucht man nicht dafür ist das using da, damit man nicht vergessen kann close/dispose aufzurufen.
    Besonders falls eine exception geworfen wird, wird durch das using statemant definitiv immer beim verlassen des blocks close/dispose aufgerufen.



  • @hkdd sagte in Warum klappt Binary bei mir nicht:

    var r1 = fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    

    r1 ist m.E. doch die zurück gegebene tatsächlich gelesene Länge, also ein int-Wert.
    Macht r1.Wait() dann einen Sinn ?

    In den gefundenen ReadAsync Beispielen sieht es etwa so aus

    var r1ReadLen = await fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    

    Alle asynchronen Methoden liefern ein Task (für void) oder Task<T>-Objekt zurück, auch Stream.ReadAsync.
    Der eigentliche Rückgabewert steht dann in Result.



  • @Th69
    Im Debugger habe ich mir r1 angesehen. r1.Result ist die gelesene Länge. Es gibt andere Infos. Und offenbar auch Funktionen, wie r1.Wait(), die man benutzen kann.

    ich habe jetzt beide Dateien mit ReadAsync gelesen und die Puffer vergrößert.
    Werden die Puffer tatsächlich zeitlich parallel / gleichzeitig und nicht mehr nacheinander gelesen ?

            //=================================================
            // Datei 1 und 2 lesen und vergleichen
            //=================================================
            private bool VergleicheDateien(string pDsn1, string pDsn2, Int64 lenFile, string pPfad)
            {
                bool rc = true;
                Int64 RestLen = lenFile; // Dateilänge beider Dateien
                Int64 LeseLen = Math.Min(RestLen, MaxPuffL);
    
                using (FileStream fs1 = new FileStream(pDsn1, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
                using (FileStream fs2 = new FileStream(pDsn2, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.SequentialScan))
                {
                    while (LeseLen > 0 && rc)
                    {
                        Application.DoEvents();
                        if (Abbruch > 0) { return false; }
    
                        GesBytes += LeseLen; // Anzahl gelesene Bytes gesamt
    
                        this.Text = "CompHk " + GesBytes.ToString("###,###,###,###,##0") + " Bytes " + pPfad;
                         
                        var r1 = fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
                        var r2 = fs2.ReadAsync(ByPu2, 0, (int)LeseLen);
                        r1.Wait();
                        r2.Wait();
    
                        AnzPuff++;                 // Anzahl verglichene Puffer
    
                        if (LeseLen < 9)
                        {
                            for (int b = 0; b < LeseLen; b++)
                            {
                                if (ByPu1[b] != ByPu2[b])
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                            }
                            break;
                        }
    
                        switch (VergleichsMethode) // Welche Art des Vergleiches
                        {
                            case compSequenceEqual: // C# interne Funktion
                                if (!(ByPu1.Take((int)LeseLen).SequenceEqual(ByPu2.Take((int)LeseLen))))
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compMemCmp: // [DllImport]  msvcrt.dll
                                if (memcmp(ByPu1, ByPu2, LeseLen) != 0)
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compForNxt: // C# interner Byte-für-Byte-Vergleich
                                for (int b = 0; b < LeseLen; b++)
                                {
                                    if (ByPu1[b] != ByPu2[b])
                                    {
                                        rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                    }
                                }
                                break;
                            case compUnsafe: // unsafe MemCmp
                                if (!MemCmp(ByPu1, ByPu2, (int)LeseLen))
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compRtlCompareMemory: // [DllImport] kernel32.dll RtlCompareMemory
    
                                IntPtr len = (IntPtr)LeseLen;
                                //IntPtr rc = RtlCompareMemory(ByPu1, ByPu2, len);
                                var rCod = RtlCompareMemory(ByPu1, ByPu2, len);
    
                                if (rCod != len)
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                            case compCompareByteArray: // [DllImport] CompareByteArray.dll von HK
                                if (CompareByteArray(ByPu1, ByPu2, (int)LeseLen) != 0)
                                {
                                    rc = false;      // Es gibt Differenzen, Vergleich abbrechen
                                }
                                break;
                        } // switch (VergleichsMethode)
    
                        RestLen -= LeseLen;
                        LeseLen = Math.Min(RestLen, MaxPuffL);
    
                    } //   while (LeseLen > 0 && rc)
                }
    
                if (rc) { AnzFilesOK++; } // es gibt keine Differenzen
                else    { ByteDiff++; }   // es gibt Differenzen
    
                return rc;
    
            } // static bool VergleicheDateien(string pDsn1, string pDsn2, Int64 lenFile)
    

    Hier ein paar Ergebnisse mit etwas größeren Puffern

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompCs - Dateien vergleichen - (C) 13.12.2022 Hartmut aus Dresden
    ---------------------------------------------------------------
    Parameter: N:\VideosN  N:\VideosN  
    ---------------------------------------------------------------
    Vergleich: N:\VideosN\
          mit: N:\VideosN\
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        82 Unterordner gefunden
        2.446 Dateien     gefunden
    	- davon 2.446 identische Dateien verglichen.
        Es wurden 208.144.569.612 Bytes = 203.266.181 K-Bytes verglichen.
        133.902 Puffer gelesen, Pufferlänge: 1.572.864 Bytes.
        Start 07:30:05  Ende 07:55:57  Dauer 00:25:52.0
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompCs - Dateien vergleichen - (C) 14.12.2022 Hartmut aus Dresden
    ---------------------------------------------------------------
    Parameter: N:\VideosN  N:\VideosN  
    ---------------------------------------------------------------
    Vergleich: N:\VideosN\    MaxPuffL = 0x00180000; // Pufferlänge
          mit: N:\VideosN\    var r1 = fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        82 Unterordner gefunden
        2.446 Dateien     gefunden
    	- davon 2.446 identische Dateien verglichen.
        Es wurden 208.144.569.612 Bytes = 203.266.181 K-Bytes verglichen.
        133.902 Puffer gelesen, Pufferlänge: 1.572.864 Bytes.
        Start 08:24:28  Ende 08:50:29  Dauer 00:26:00.4
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompCs - Dateien vergleichen - (C) 14.12.2022 Hartmut aus Dresden
    ---------------------------------------------------------------
    Parameter: N:\VideosN  N:\VideosN  
    ---------------------------------------------------------------
    Vergleich: N:\VideosN\    MaxPuffL = 0x08000000; // Pufferlänge
          mit: N:\VideosN\    var r1 = fs1.ReadAsync(ByPu1, 0, (int)LeseLen);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        82 Unterordner gefunden
        2.446 Dateien     gefunden
    	- davon 2.446 identische Dateien verglichen.
        Es wurden 208.144.569.612 Bytes = 203.266.181 K-Bytes verglichen.
        3.424 Puffer gelesen, Pufferlänge: 134.217.728 Bytes.
        Start 08:51:59  Ende 09:19:00  Dauer 00:27:00.9
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompCs - Dateien vergleichen - (C) 14.12.2022 Hartmut aus Dresden
    ---------------------------------------------------------------
    Parameter: N:\VideosN  N:\VideosN  
    ---------------------------------------------------------------
    Vergleich: N:\VideosN\    MaxPuffL = 0x00800000; // Pufferlänge
          mit: N:\VideosN\    fs1 und fs2 ReadAsync 
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        82 Unterordner gefunden
        2.446 Dateien     gefunden
    	- davon 2.446 identische Dateien verglichen.
        Es wurden 208.144.569.612 Bytes = 203.266.181 K-Bytes verglichen.
        26.474 Puffer gelesen, Pufferlänge: 8.388.608 Bytes.
        Start 09:23:35  Ende 09:48:57  Dauer 00:25:21.5
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    


  • @hkdd

    Werden die Puffer tatsächlich zeitlich parallel / gleichzeitig und nicht mehr nacheinander gelesen ?

    Ja. Dazu reicht es allerdings wenn man einen der beiden Reads (den ersten) "async" macht. Das erste ReadAsync startet dabei das Lesen des Blocks aus dem 1. File. Daneben läuft das Programm weiter und kann den 2. Read synchron machen. Wenn der 2. Read fertig ist, muss man noch warten dass der erste, asynchrone auch fertig ist - könnte ja sein dass der 2. Read aus irgend einem Grund schneller war. Das macht das r1.Wait().

    Bringt aber nichts, wenn du 2x vom selben Laufwerk liest. Weil Zugriffe auf das selbe Laufwerk werden nicht schneller, nur weil man 2 parallel macht. Es könnte die Sache sogar erheblich langsamer machen. Wenn es allerdings verschiedene Laufwerke sind, dann bringt es u.U. viel, denn dann können beide Laufwerke gleichzeitig lesen.

    Kann, muss aber nicht, weil das OS evtl. "read ahead" macht. Ob das passiert und wie gut es funktioniert hängt von einigen Faktoren ab. U.a. der OS Version und der Puffergrösse. (Read ahead wird nur bis zu einer maximalen Puffergrösse gemacht.)

    Aktuell scheinst du mit 2x dem selben Verzeichnis zu testen. Das macht mMn. eher wenig Sinn wenn du Performance-Tests machen willst. Wenn du das Programm auf den Einsatz mit 2 verschiedenen Laufwerken optimieren willst, dann solltest du auch mit 2 verschiedenen Laufwerken testen. Bzw. wenn du das Programm auf den Einsatz mit 2 Verzeichnissen auf dem selben Laufwerk optimieren willst, dann solltest du auch mit 2 verschiedenen Verzeichnissen auf dem selben Laufwerk testen. Und wenn du möglichst gute Performance in beiden Fällen haben willst, dann solltest du auch beide testen 🙂

    So wie du es jetzt machst, also 2x das selbe Verzeichnis lesen, wird halt effektiv nur 1x wirklich vom Laufwerk gelesen. Beim 2. mal Lesen kommen die Daten dann aus dem File Cache - weil's ja das selbe File ist.



  • @hustbaer sagte in Warum klappt Binary bei mir nicht:

    weil's ja das selbe File ist

    Danke für Deine Erläuterungen. Das ist mir schon klar und in der Anwendung will ich ja damit gesicherte Daten vergleichen, die stehen dann auf einer externen HDD oder evtl. sogar auf eine DVD / Blueray oder einem USB-Stick oder einem Netzlaufwerk.
    Weil das Delphi-Programm so deutlich schneller war, wollte ich den Overhead von C# ermitteln, also alles, was mit dem Lesen und auch dem Vergleichen gar nichts zu tun hat, nur der Grundaufwand für das Lesen der Directorys usw.
    Deshalb habe ich ja auch Test-Schalter, mit denen ich das Einlesen und Vergleichen überspringen kann.
    Das habe ich inzwischen ganz gut hinbekommen, so dass der Unterschied zum Delphi-Programm kaum noch erkennbar ist.
    Solche weiteren Optimierungen, wie asynchrones / zeilich paralleles Lesen gibt es bei Delphi 7 nicht. Die neueren Delphi-Versionen können das sicherlich auch.



  • @hustbaer sagte in Warum klappt Binary bei mir nicht:

    dann solltest du auch mit 2 verschiedenen Laufwerken testen

    Das habe ich jetzt gemacht

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompHKw - Dateien Vergleichen - (C) 12.12.2022 Hartmut aus Dresden                DELPHI Lauf 1
    -----------------------------------------------------------------------------------------------------------
    Parameter: "V:\#Musik\#MP3-aus-WAV\#TB-MP3" "Z:\#Musik\#MP3-aus-WAV\#TB-MP3" "/U" "/VN" "/F" "/M:200" "/A"
    -----------------------------------------------------------------------------------------------------------
    Vergleich: V:\#Musik\#MP3-aus-WAV\#TB-MP3\                   DELPHI Lauf 1
          mit: Z:\#Musik\#MP3-aus-WAV\#TB-MP3\
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    4.880.Datei: V:\#Musik\#MP3-aus-WAV...ger\72-gs-638 Lang Lang ist´s her [Heino].mp3
    =================================================================
        246 Unter-Pfade gefunden   - identisch.
      4.880 Dateien     gefunden   - und verglichen...
      4.880 Dateien     verglichen - identisch.
          Es wurden 25.148.066.175 Bytes = 24.558.658 K-Bytes verglichen
          Start 18:30:05  Ende 18:34:55  Dauer 00:04:50
    ========================================================<Ende>===
    Linke MausTaste / ESC = Schließen   Rechte MausTaste / F1 = Info
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompHKw - Dateien Vergleichen - (C) 12.12.2022 Hartmut aus Dresden                DELPHI Lauf 2
    -----------------------------------------------------------------------------------------------------------
    Parameter: "V:\#Musik\#MP3-aus-WAV\#TB-MP3" "Z:\#Musik\#MP3-aus-WAV\#TB-MP3" "/U" "/VN" "/F" "/M:200" "/A"
    -----------------------------------------------------------------------------------------------------------
    Vergleich: V:\#Musik\#MP3-aus-WAV\#TB-MP3\   
          mit: Z:\#Musik\#MP3-aus-WAV\#TB-MP3\
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    4.880.Datei: V:\#Musik\#MP3-aus-WAV...ger\72-gs-638 Lang Lang ist´s her [Heino].mp3
    =================================================================
        246 Unter-Pfade gefunden   - identisch.
      4.880 Dateien     gefunden   - und verglichen...
      4.880 Dateien     verglichen - identisch.
          Es wurden 25.148.066.175 Bytes = 24.558.658 K-Bytes verglichen
          Start 18:37:00  Ende 18:42:18  Dauer 00:05:18
    ========================================================<Ende>===
    Linke MausTaste / ESC = Schließen   Rechte MausTaste / F1 = Info
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompCs - Dateien vergleichen - (C) 14.12.2022 Hartmut aus Dresden           C#  Lauf1
    ---------------------------------------------------------------
    Parameter: V:\#Musik\#MP3-aus-WAV\#TB-MP3  Z:\#Musik\#MP3-aus-WAV\#TB-MP3  
    ---------------------------------------------------------------
    Vergleich: V:\#Musik\#MP3-aus-WAV\#TB-MP3\
          mit: Z:\#Musik\#MP3-aus-WAV\#TB-MP3\
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        246 Unterordner gefunden
        4.880 Dateien     gefunden
    	- davon 4.880 identische Dateien verglichen.
        Es wurden 25.148.066.175 Bytes = 24.558.658 K-Bytes verglichen.
        18.447 Puffer gelesen, Pufferlänge: 1.572.864 Bytes.
        Start 18:43:06  Ende 18:44:52  Dauer 00:01:45.6
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CompCs - Dateien vergleichen - (C) 14.12.2022 Hartmut aus Dresden           C#  Lauf2
    ---------------------------------------------------------------
    Parameter: V:\#Musik\#MP3-aus-WAV\#TB-MP3  Z:\#Musik\#MP3-aus-WAV\#TB-MP3  
    ---------------------------------------------------------------
    Vergleich: V:\#Musik\#MP3-aus-WAV\#TB-MP3\
          mit: Z:\#Musik\#MP3-aus-WAV\#TB-MP3\
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ============================================================
        246 Unterordner gefunden
        4.880 Dateien     gefunden
    	- davon 4.880 identische Dateien verglichen.
        Es wurden 25.148.066.175 Bytes = 24.558.658 K-Bytes verglichen.
        18.447 Puffer gelesen, Pufferlänge: 1.572.864 Bytes.
        Start 18:45:35  Ende 18:49:15  Dauer 00:03:39.7             statt 9:15 bei C# ALT
    ===================================================<Ende>===
      ESC = Programm beenden
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    Die Delphi-Version braucht etwa 5 Minuten, die neue C#-Version 2 bis 3 Minuten und meine alte C# Version über 9 Minuten.
    Es werden mp3-Dateien auf einer internen sATA3-HDD mit einer USB3-Sicherungs-HDD verglichen.



  • @hkdd
    D.h. das Ding ist jetzt nicht nur gleich schnell, sondern schneller. Nice 🙂

    Noch ein Tip: wenn's um's Lesen von Files geht, spielt ja der File-Cache immer mit rein. Dadurch bekommst du dann unterschiedliche Zeiten je nachdem ob du mit warmem oder kaltem Cache testest. Wenn du nicht für jeden Test den PC rebooten willst, kannst du mit USB HDDs testen. In deinem Fall bräuchtest du halt 2 USB HDDs. Wenn du die vor jedem Test ab- und wieder ansteckst hast du wieder kalte Caches.


Anmelden zum Antworten