Array.Copy vs Buffer.BlockCopy

124

Array.Copy und Buffer.BlockCopy machen beide dasselbe, BlockCopyzielen jedoch auf schnelles primitives Array-Kopieren auf Byte-Ebene ab, während dies Copydie allgemeine Implementierung ist. Meine Frage ist - unter welchen Umständen sollten Sie verwenden BlockCopy? Sollten Sie es zu irgendeinem Zeitpunkt verwenden, wenn Sie Arrays vom primitiven Typ kopieren, oder sollten Sie es nur verwenden, wenn Sie für die Leistung codieren? Ist die Verwendung von Buffer.BlockCopyOver von Natur aus gefährlich Array.Copy?

thecoop
quelle
3
Vergiss nicht Marshal.Copy:-). Nun, verwenden Sie Array.Copyfür Referenztypen, komplexe Werttypen und, wenn sich der Typ nicht ändert, Buffer.BlockCopyfür die "Konvertierung" zwischen Werttypen, Bytearrays und Bytemagie. F.ex. Die Kombination mit StructLayoutist ziemlich mächtig, wenn Sie wissen, was Sie tun. In Bezug auf die Leistung scheint ein nicht verwalteter Aufruf von memcpy/ cpblkder schnellste zu sein - siehe code4k.blogspot.nl/2010/10/… .
Atlaste
1
Ich habe einige Benchmark-Tests mit durchgeführt byte[]. Es gab keinen Unterschied in der Release-Version. Manchmal Array.Copy, manchmal Buffer.BlockCopy(etwas) schneller.
Bitterblue
Neue umfassende Antwort, die gerade unten veröffentlicht wurde. Beachten Sie, dass in Fällen mit kleinen Puffergrößen das explizite Kopieren von Schleifen normalerweise am besten ist.
Spezielle Sauce
Ich glaube nicht, dass sie immer das Gleiche tun - Sie können Array.Copy nicht verwenden, um beispielsweise ein Array von Ints in ein Array von Bytes zu kopieren
mcmillab
Array.Copyist eher eine spezialisierte Version - zum Beispiel kann sie nur die gleichen Rang-Arrays kopieren.
Astrowalker

Antworten:

59

Da die Parameter Buffer.BlockCopyeher bytebasiert als indexbasiert sind, ist es wahrscheinlicher, dass Sie Ihren Code vermasseln, als wenn Sie ihn verwenden Array.Copy. Daher würde ich ihn nur Buffer.BlockCopyin einem leistungskritischen Abschnitt meines Codes verwenden.

MusiGenesis
quelle
9
Stimme voll und ganz zu. Bei Buffer.BlockCopy ist zu viel Platz für Fehler. Halten Sie es einfach und versuchen Sie nicht, Saft aus Ihrem Programm herauszupressen, bis Sie wissen, wo sich der Saft befindet (Profiling).
Stephen
5
Was ist, wenn Sie es mit einem Byte [] zu tun haben? Gibt es noch andere Fallstricke bei BlockCopy?
Thecoop
4
@thecoop: Wenn Sie es mit einem Byte [] zu tun haben, ist es wahrscheinlich in Ordnung, BlockCopy zu verwenden, es sei denn, die Definition von "Byte" wird später in etwas anderes als ein Byte geändert, was sich wahrscheinlich ziemlich negativ auf andere Teile von auswirken würde Ihr Code trotzdem. :) Das einzige andere mögliche Problem ist, dass BlockCopy nur gerade Bytes ausführt, sodass die Endianness nicht berücksichtigt wird. Dies würde jedoch nur auf einem Nicht-Windows-Computer zum Tragen kommen und nur, wenn Sie den Code vermasselt hätten den ersten Platz. Es kann auch einen merkwürdigen Unterschied geben, wenn Sie Mono verwenden.
MusiGenesis
6
In meinen eigenen Tests ist Array.Copy () in der Leistung Buffer.BlockCopy () sehr ähnlich. Buffer.BlockCopy ist für mich durchweg <10% schneller, wenn es um 640-Element-Byte-Arrays geht (das ist die Sorte, die mich am meisten interessiert). Sie sollten jedoch Ihre eigenen Tests mit Ihren eigenen Daten durchführen, da diese vermutlich abhängig von den Daten, Datentypen, Arraygrößen usw. variieren. Ich sollte beachten, dass beide Methoden ungefähr 3x schneller sind als Array.Clone () und vielleicht 20x schneller als das Kopieren in eine for-Schleife.
Ken Smith
3
@ KevinMiller: Äh, UInt16ist zwei Bytes pro Element. Wenn Sie dieses Array zusammen mit der Anzahl der Elemente im Array an BlockCopy übergeben, wird natürlich nur die Hälfte des Arrays kopiert. Damit dies ordnungsgemäß funktioniert, müssen Sie die Anzahl der Elemente mal die Größe jedes Elements (2) als Längenparameter übergeben. msdn.microsoft.com/en-us/library/… und suchen Sie INT_SIZEin den Beispielen nach.
MusiGenesis
129

Auftakt

Ich bin spät auf der Party, aber mit 32.000 Views lohnt es sich, das richtig zu machen. Der größte Teil des Mikrobenchmarking-Codes in den bisher veröffentlichten Antworten weist einen oder mehrere schwerwiegende technische Mängel auf, darunter das Nichtverschieben von Speicherzuordnungen aus den Testschleifen (was zu schwerwiegenden GC-Artefakten führt), das Nicht-Testen von variablen vs. deterministischen Ausführungsabläufen, JIT-Aufwärmen, und nicht die Variabilität innerhalb des Tests verfolgen. Darüber hinaus testeten die meisten Antworten nicht die Auswirkungen unterschiedlicher Puffergrößen und unterschiedlicher primitiver Typen (in Bezug auf 32-Bit- oder 64-Bit-Systeme). Um diese Frage umfassender zu beantworten, habe ich sie an ein von mir entwickeltes benutzerdefiniertes Microbenchmarking-Framework angeschlossen, das die meisten gängigen "Fallstricke" so weit wie möglich reduziert. Die Tests wurden im .NET 4.0-Release-Modus sowohl auf einem 32-Bit-Computer als auch auf einem 64-Bit-Computer ausgeführt. Die Ergebnisse wurden über 20 Testläufe gemittelt, in denen jeder Lauf 1 Million Versuche pro Methode aufwies. Die getesteten primitiven Typen warenbyte(1 Byte), int(4 Byte) und double(8 Byte). Drei Methoden wurden getestet: Array.Copy(), Buffer.BlockCopy()und einfach per-Indexzuordnung in einer Schleife. Die Daten sind zu umfangreich, um hier veröffentlicht zu werden, daher werde ich die wichtigen Punkte zusammenfassen.

Die Imbissbuden

  • Wenn Ihre Pufferlänge etwa 75-100 oder weniger beträgt, ist eine explizite Schleifenkopierroutine normalerweise schneller (um etwa 5%) als einer Array.Copy()oder Buffer.BlockCopy()alle drei primitiven Typen, die sowohl auf 32-Bit- als auch auf 64-Bit-Computern getestet wurden. Darüber hinaus weist die explizite Schleifenkopierroutine im Vergleich zu den beiden Alternativen eine deutlich geringere Variabilität der Leistung auf. Die gute Leistung ist fast sicher auf die Lokalität der Referenz zurückzuführen, die vom Speicher-Caching der CPU L1 / L2 / L3 in Verbindung mit keinem Overhead für Methodenaufrufe ausgenutzt wird.
    • Nur für doublePuffer auf 32-Bit-Computern : Die explizite Schleifenkopierroutine ist für alle getesteten Puffergrößen bis zu 100.000 besser als beide Alternativen. Die Verbesserung ist 3-5% besser als bei den anderen Methoden. Dies liegt daran, dass die Leistung von Array.Copy()und das Buffer.BlockCopy()Übergeben der nativen 32-Bit-Breite vollständig beeinträchtigt wird. Daher gehe ich davon aus, dass der gleiche Effekt auch für longPuffer gelten würde .
  • Bei Puffergrößen über ~ 100 wird das explizite Kopieren von Schleifen schnell viel langsamer als bei den beiden anderen Methoden (mit der einen Ausnahme, die gerade erwähnt wurde). Der Unterschied ist am deutlichsten bei byte[], wo das explizite Kopieren von Schleifen bei großen Puffergrößen 7x oder langsamer werden kann.
  • Im Allgemeinen für alle 3 getesteten primitiven Typen und über alle Puffergrößen hinweg Array.Copy()und Buffer.BlockCopy()nahezu identisch durchgeführt. Im Durchschnitt Array.Copy()scheint eine sehr leichte Kante von etwa 2% oder weniger Zeit in Anspruch genommen zu haben (aber 0,2% - 0,5% besser ist typisch), obwohl Buffer.BlockCopy()sie gelegentlich geschlagen wurde. Hat aus unbekannten Gründen Buffer.BlockCopy()eine deutlich höhere Variabilität innerhalb des Tests als Array.Copy(). Dieser Effekt konnte nicht beseitigt werden, obwohl ich mehrere Abschwächungen versuchte und keine funktionsfähige Theorie darüber hatte, warum.
  • Da Array.Copy()es sich um eine "intelligentere", allgemeinere und viel sicherere Methode handelt, die nicht nur geringfügig schneller ist und im Durchschnitt eine geringere Variabilität aufweist, sollte sie Buffer.BlockCopy()in fast allen gängigen Fällen vorgezogen werden. Der einzige Anwendungsfall Buffer.BlockCopy(), der wesentlich besser ist, besteht darin, dass die Werttypen des Quell- und Zielarrays unterschiedlich sind (wie in Ken Smiths Antwort ausgeführt). Obwohl dieses Szenario nicht üblich ist, Array.Copy()kann es hier aufgrund des kontinuierlichen "sicheren" Wertgusstyps im Vergleich zum direkten Gießen von sehr schlecht abschneiden Buffer.BlockCopy().
  • Weitere Hinweise von außerhalb von StackOverflow, Array.Copy()die schneller sind als Buffer.BlockCopy()beim Kopieren von Arrays gleichen Typs, finden Sie hier .
Spezielle Sauce
quelle
Als Nebenwirkung stellt sich auch heraus , dass ist um eine Arraylänge von 100 , wenn .NET ist Array.Clear()zuerst beginnt (der Einstellung eine explizite Schleifenbelegung Clearing eines Arrays zu schlagen false, 0oder null). Dies steht im Einklang mit meinen ähnlichen Befunden oben. Diese separaten Benchmarks wurden hier online entdeckt: manski.net/2012/12/net-array-clear-vs-arrayx-0-performance
Special Sauce
Wenn Sie Puffergröße sagen; Meinst du in Bytes oder Elementanzahl?
Dmarra
In meiner obigen Antwort beziehen sich sowohl "Pufferlänge" als auch "Puffergröße" im Allgemeinen auf die Elementanzahl.
Spezielle Soße
Ich habe ein Beispiel, in dem ich häufig ungefähr 8 Datenbytes in einen Puffer kopieren muss, der von einer um 5 Bytes versetzten Quelle liest. Ich fand, dass die explizite Schleifenkopie wesentlich schneller ist als die Verwendung von Buffer.BlockCopy oder Array.Copy. Loop Results for 1000000 iterations 17.9515ms. Buffer.BlockCopy Results for 1000000 iterations 39.8937ms. Array.Copy Results for 1000000 iterations 45.9059ms Wenn die Kopiergröße jedoch> ~ 20 Byte ist, ist die explizite Schleife erheblich langsamer.
Tod Cunningham
@TodCunningham, 8 Datenbytes? Du meinst langes Äquivalent? Entweder ein einzelnes Element umwandeln und kopieren (absolut schnell) oder diese Schleife einfach manuell abrollen.
Astrowalker
67

Ein weiteres Beispiel für die Verwendung Buffer.BlockCopy()ist, wenn Sie ein Array von Grundelementen (z. B. Kurzschlüsse) erhalten und dieses in ein Array von Bytes konvertieren müssen (z. B. für die Übertragung über ein Netzwerk). Ich verwende diese Methode häufig, wenn ich mit Audio vom Silverlight AudioSink arbeite. Das Beispiel wird als short[]Array bereitgestellt, Sie müssen es jedoch in ein byte[]Array konvertieren, wenn Sie das Paket erstellen, an das Sie senden Socket.SendAsync(). Sie können BitConverterdas Array einzeln verwenden und durchlaufen, aber es ist viel schneller (ungefähr 20x in meinen Tests), nur um dies zu tun:

Buffer.BlockCopy(shortSamples, 0, packetBytes, 0, shortSamples.Length * sizeof(short)).  

Und der gleiche Trick funktioniert auch umgekehrt:

Buffer.BlockCopy(packetBytes, readPosition, shortSamples, 0, payloadLength);

Dies ist ungefähr so ​​nah wie in sicherem C # an der (void *)in C und C ++ üblichen Art der Speicherverwaltung.

Ken Smith
quelle
6
Das ist eine coole Idee - stoßen Sie jemals auf Probleme mit Endianness?
Phillip
Ja, ich denke, dass Sie abhängig von Ihrem Szenario auf dieses Problem stoßen könnten. Meine eigenen Szenarien waren normalerweise entweder (a) ich muss zwischen Byte-Arrays und kurzen Arrays auf demselben Computer hin und her wechseln, oder (b) ich weiß zufällig, dass ich meine Daten an Computer desselben sende Endianness, und die ich die entfernte Seite steuere. Wenn Sie jedoch ein Protokoll verwenden, für das der Remotecomputer erwartet, dass Daten in Netzwerkreihenfolge und nicht in Hostreihenfolge gesendet werden, führt dieser Ansatz zu Problemen.
Ken Smith
Ken hat auch einen Artikel über BlockCopy in seinem Blog: blog.wouldbetheologian.com/2011/11/…
Drew Noakes
4
Beachten Sie, dass Sie dies seit .Net Core 2.1 ohne Kopieren tun können. MemoryMarshal.AsBytes<T>oder MemoryMarshal.Cast<TFrom, TTo>lassen Sie Ihre Sequenz eines Primitivs als Sequenz eines anderen Primitivs interpretieren.
Timo
16

Aufgrund meiner Tests ist die Leistung kein Grund, Buffer.BlockCopy Array.Copy vorzuziehen. Nach meinem Test ist Array.Copy tatsächlich schneller als Buffer.BlockCopy.

var buffer = File.ReadAllBytes(...);

var length = buffer.Length;
var copy = new byte[length];

var stopwatch = new Stopwatch();

TimeSpan blockCopyTotal = TimeSpan.Zero, arrayCopyTotal = TimeSpan.Zero;

const int times = 20;

for (int i = 0; i < times; ++i)
{
    stopwatch.Start();
    Buffer.BlockCopy(buffer, 0, copy, 0, length);
    stopwatch.Stop();

    blockCopyTotal += stopwatch.Elapsed;

    stopwatch.Reset();

    stopwatch.Start();
    Array.Copy(buffer, 0, copy, 0, length);
    stopwatch.Stop();

    arrayCopyTotal += stopwatch.Elapsed;

    stopwatch.Reset();
}

Console.WriteLine("bufferLength: {0}", length);
Console.WriteLine("BlockCopy: {0}", blockCopyTotal);
Console.WriteLine("ArrayCopy: {0}", arrayCopyTotal);
Console.WriteLine("BlockCopy (average): {0}", TimeSpan.FromMilliseconds(blockCopyTotal.TotalMilliseconds / times));
Console.WriteLine("ArrayCopy (average): {0}", TimeSpan.FromMilliseconds(arrayCopyTotal.TotalMilliseconds / times));

Beispielausgabe:

bufferLength: 396011520
BlockCopy: 00:00:02.0441855
ArrayCopy: 00:00:01.8876299
BlockCopy (average): 00:00:00.1020000
ArrayCopy (average): 00:00:00.0940000
Kevin
quelle
1
Es tut mir leid, dass diese Antwort eher ein Kommentar ist, aber es war zu lang für einen Kommentar. Da der Konsens zu sein schien, dass Buffer.BlockCopy besser für die Leistung ist, dachte ich, dass jeder wissen sollte, dass ich diesen Konsens nicht mit Tests bestätigen konnte.
Kevin
10
Ich denke, es gibt ein Problem mit Ihrer Testmethode. Der größte Zeitunterschied, den Sie feststellen, ist das Ergebnis des Hochfahrens der Anwendung, des Zwischenspeicherns selbst, des Ausführens der JIT usw. Versuchen Sie es mit einem kleineren Puffer, aber einige tausend Mal; und wiederholen Sie dann den gesamten Test innerhalb einer Schleife ein halbes Dutzend Mal und achten Sie nur auf den letzten Lauf. Bei meinen eigenen Tests läuft Buffer.BlockCopy () für 640-Byte-Arrays möglicherweise 5% schneller als Array.Copy (). Nicht viel schneller, aber ein bisschen.
Ken Smith
2
Ich habe dasselbe für ein bestimmtes Problem gemessen und konnte keinen Leistungsunterschied zwischen Array.Copy () und Buffer.BlockCopy () feststellen . Wenn überhaupt, hat BlockCopy unsicher eingeführt, was meine App in einem Fall tatsächlich getötet hat .
Gatopeich
1
Genau wie beim Hinzufügen von Array.Copy wird die Quellposition lange unterstützt, sodass beim Aufbrechen in Big- Byte-Arrays keine Ausnahme außerhalb des Bereichs ausgelöst wird.
Alxwest
2
Basierend auf den Tests, die ich gerade durchgeführt habe ( bitbucket.org/breki74/tutis/commits/… ), würde ich sagen, dass es keinen praktischen Leistungsunterschied zwischen den beiden Methoden gibt, wenn Sie mit Byte-Arrays arbeiten.
Igor Brejc
4

ArrayCopy ist schlauer als BlockCopy. Es wird herausgefunden, wie Elemente kopiert werden, wenn Quelle und Ziel dasselbe Array sind.

Wenn wir ein int-Array mit 0,1,2,3,4 füllen und anwenden:

Array.Copy (Array, 0, Array, 1, Array.Length - 1);

Am Ende haben wir erwartungsgemäß 0,0,1,2,3.

Versuchen Sie dies mit BlockCopy und wir erhalten: 0,0,2,3,4. Wenn ich array[0]=-1danach zuweise, wird es wie erwartet -1,0,2,3,4, aber wenn die Array-Länge gerade ist, wie 6, erhalten wir -1,256,2,3,4,5. Gefährliches Zeug. Verwenden Sie BlockCopy nur zum Kopieren eines Byte-Arrays in ein anderes.

Es gibt einen anderen Fall, in dem Sie Array.Copy nur verwenden können: Wenn die Arraygröße länger als 2 ^ 31 ist. Array.Copy hat eine Überladung mit einem Größenparameter long. BlockCopy hat das nicht.

user3523091
quelle
2
Die Ergebnisse Ihrer Tests mit BlockCopy sind nicht unerwartet. Dies liegt daran, dass die Blockkopie versucht, Datenblöcke gleichzeitig und nicht jeweils ein Byte zu kopieren. Auf einem 32-Bit-System werden jeweils 4 Bytes kopiert, auf einem 64-Bit-System werden jeweils 8 Bytes kopiert.
Pharap
Also erwartet undefiniertes Verhalten.
Binki
2

Um dieses Argument abzuwägen: Wenn man nicht aufpasst, wie sie diesen Benchmark erstellen, können sie leicht irregeführt werden. Ich habe einen sehr einfachen Test geschrieben, um dies zu veranschaulichen. Wenn ich in meinem Test unten die Reihenfolge meiner Tests zwischen dem Starten von Buffer.BlockCopy zuerst oder Array.Copy vertausche, ist diejenige, die zuerst geht, fast immer die langsamste (obwohl es eine enge ist). Dies bedeutet, dass ich aus einer Reihe von Gründen, auf die ich nicht eingehen werde, die Tests einfach mehrmals ausführen werde, insbesondere nacheinander, keine genauen Ergebnisse liefert.

Ich habe darauf zurückgegriffen, den Test so beizubehalten, wie er bei jeweils 1000000 Versuchen für ein Array von 1000000 sequentiellen Doppeln ist. Allerdings ignoriere ich dann dann die ersten 900000 Zyklen und mittle den Rest. In diesem Fall ist der Puffer überlegen.

private static void BenchmarkArrayCopies()
        {
            long[] bufferRes = new long[1000000];
            long[] arrayCopyRes = new long[1000000];
            long[] manualCopyRes = new long[1000000];

            double[] src = Enumerable.Range(0, 1000000).Select(x => (double)x).ToArray();

            for (int i = 0; i < 1000000; i++)
            {
                bufferRes[i] = ArrayCopyTests.ArrayBufferBlockCopy(src).Ticks;
            }

            for (int i = 0; i < 1000000; i++)
            {
                arrayCopyRes[i] = ArrayCopyTests.ArrayCopy(src).Ticks;
            }

            for (int i = 0; i < 1000000; i++)
            {
                manualCopyRes[i] = ArrayCopyTests.ArrayManualCopy(src).Ticks;
            }

            Console.WriteLine("Loop Copy: {0}", manualCopyRes.Average());
            Console.WriteLine("Array.Copy Copy: {0}", arrayCopyRes.Average());
            Console.WriteLine("Buffer.BlockCopy Copy: {0}", bufferRes.Average());

            //more accurate results - average last 1000

            Console.WriteLine();
            Console.WriteLine("----More accurate comparisons----");

            Console.WriteLine("Loop Copy: {0}", manualCopyRes.Where((l, i) => i > 900000).ToList().Average());
            Console.WriteLine("Array.Copy Copy: {0}", arrayCopyRes.Where((l, i) => i > 900000).ToList().Average());
            Console.WriteLine("Buffer.BlockCopy Copy: {0}", bufferRes.Where((l, i) => i > 900000).ToList().Average());
            Console.ReadLine();
        }

public class ArrayCopyTests
    {
        private const int byteSize = sizeof(double);

        public static TimeSpan ArrayBufferBlockCopy(double[] original)
        {
            Stopwatch watch = new Stopwatch();
            double[] copy = new double[original.Length];
            watch.Start();
            Buffer.BlockCopy(original, 0 * byteSize, copy, 0 * byteSize, original.Length * byteSize);
            watch.Stop();
            return watch.Elapsed;
        }

        public static TimeSpan ArrayCopy(double[] original)
        {
            Stopwatch watch = new Stopwatch();
            double[] copy = new double[original.Length];
            watch.Start();
            Array.Copy(original, 0, copy, 0, original.Length);
            watch.Stop();
            return watch.Elapsed;
        }

        public static TimeSpan ArrayManualCopy(double[] original)
        {
            Stopwatch watch = new Stopwatch();
            double[] copy = new double[original.Length];
            watch.Start();
            for (int i = 0; i < original.Length; i++)
            {
                copy[i] = original[i];
            }
            watch.Stop();
            return watch.Elapsed;
        }
    }

https://github.com/chivandikwa/Random-Benchmarks

Thulani Chivandikwa
quelle
5
Ich sehe keine Timing-Ergebnisse in Ihrer Antwort. Bitte geben Sie die Konsolenausgabe an.
ToolmakerSteve
0

Ich möchte nur meinen Testfall hinzufügen, der erneut zeigt, dass BlockCopy keinen 'PERFORMANCE'-Vorteil gegenüber Array.Copy hat. Sie scheinen im Release-Modus auf meinem Computer dieselbe Leistung zu haben (beide benötigen ungefähr 66 ms, um 50 Millionen Ganzzahlen zu kopieren). Im Debug-Modus ist BlockCopy nur geringfügig schneller.

    private static T[] CopyArray<T>(T[] a) where T:struct 
    {
        T[] res = new T[a.Length];
        int size = Marshal.SizeOf(typeof(T));
        DateTime time1 = DateTime.Now;
        Buffer.BlockCopy(a,0,res,0, size*a.Length);
        Console.WriteLine("Using Buffer blockcopy: {0}", (DateTime.Now - time1).Milliseconds);
        return res;
    }

    static void Main(string[] args)
    {
        int simulation_number = 50000000;
        int[] testarray1 = new int[simulation_number];

        int begin = 0;
        Random r = new Random();
        while (begin != simulation_number)
        {
            testarray1[begin++] = r.Next(0, 10000);
        }

        var copiedarray = CopyArray(testarray1);

        var testarray2 = new int[testarray1.Length];
        DateTime time2 = DateTime.Now;
        Array.Copy(testarray1, testarray2, testarray1.Length);
        Console.WriteLine("Using Array.Copy(): {0}", (DateTime.Now - time2).Milliseconds);
    }
stt106
quelle
3
Nichts für ungut, aber dein Testergebnis ist nicht wirklich hilfreich;) Zuallererst sagt "20ms schneller" nichts aus, ohne die Gesamtzeit zu kennen. Sie haben diese beiden Tests auch sehr unterschiedlich durchgeführt. Der BlockCopy-Fall verfügt über einen zusätzlichen Methodenaufruf und die Zuordnung Ihres Zielarrays, die Sie in Ihrem Array.Copy-Fall nicht haben. Aufgrund von Multithreading-Schwankungen (möglicher Task-Switch, Core-Switch) können Sie bei jeder Testausführung problemlos unterschiedliche Ergebnisse erzielen.
Bunny83
@ Bunny83 danke für den Kommentar. Ich habe die Position des Timers leicht geändert, was jetzt einen faireren Vergleich ermöglichen sollte. Und ich bin ein bisschen überrascht, dass Blockkopie überhaupt nicht schneller ist als array.copy.
stt106