Beschreibung:
Lange habe ich gesucht um etwas zu finden, das byte-Arrays zusammenfügt.
Schnell musste es sein und absolut flexibel. Nichts gefunden, also musste ich etwas machen.
Das schnellste ist das mit dem MemoryStream.
Die Sekunden wurden erreicht bei 1.000.000 Durchläufen mit jeweils 22 Arrays a´2-8 byte.
public static byte[] ConcateByte(params object[] _Arrays) // 2,9 Sec
{
MemoryStream m = new MemoryStream();
for (int i = 0; i < _Arrays.Length; i++)
{
byte[] tmp = (byte[])_Arrays[i];
m.Write(tmp, 0, tmp.Length);
}
return m.ToArray();
}
public static byte[] ConcateByte1(params object[] _Arrays) // 3,14 Sec
{
MemoryStream m = new MemoryStream();
BinaryWriter bw = new BinaryWriter(m);
for (int i = 0; i < _Arrays.Length; i++)
{
bw.Write((byte[])_Arrays[i]);
}
return m.ToArray();
}
public static byte[] ConcateByte2(params object[] _Arrays) // 4,5 Sec
{
int[] laengen = new int[_Arrays.Length + 1];
int sum = 0;
for (int i = 0; i < _Arrays.Length; i++)
{
laengen[i + 1] = ((byte[])_Arrays[i]).Length + sum;
sum += laengen[i + 1] - sum;
}
byte[] ArrayReturn = new byte[sum];
for (int i = 0; i < _Arrays.Length; i++)
{
((byte[])_Arrays[i]).CopyTo(ArrayReturn, laengen[i]);
}
return ArrayReturn;
}
Schlagwörter: byte-Arrays zusammenfügen concate
Hier mal die generische Variante.
public static T[] Concat<T>(params T[][] arrays)
{
int length = 0;
foreach (T[] array in arrays)
{
length += array.Length;
}
T[] result = new T[length];
int start = 0;
foreach (T[] array in arrays)
{
Array.Copy(array, 0, result, start, array.Length);
start += array.Length;
}
return result;
}
Könnte schneller sein weil
Beispiel Aufruf (könnten aber auch Bytes sein)
int[] a1 = new int[] { 1, 2, 3 };
int[] a2 = new int[] { 6, 7, 8 };
int[] a3 = new int[] { 11, 22, 33 };
int[] result = Concat(a1, a2, a3); // Concat<int>(...) kann man sich sparen, das checkt der compiler
Würd mich wundern, wenn der MemoryStream, der mitwachsen und daher immer wieder umkopieren muss schneller wäre als wenn man die Länge des Resultats vorberechnet.
loop:
btst #6,$bfe001
bne.s loop
rts
Danke 0815Coder,
Würd mich wundern, wenn der MemoryStream, der mitwachsen und daher immer wieder umkopieren muss schneller wäre als wenn man die Länge des Resultats vorberechnet.
Scheinbar doch.
Mit gleichen Parametern 3,6 Sekunden. Habe aber wieder etwas gelernt und werde damit "rumprobieren".
Gruß Robert
Angeregt durch obiges Beispiel war ich absolut überzeugt, dass dies hier noch schneller ist:
public static byte[] ConcateByteArrays(params byte[][] _Arrays) // 3,1 Sec
{
MemoryStream m = new MemoryStream();
foreach (byte[] array in _Arrays)
{
m.Write(array, 0, array.Length);
}
return m.ToArray();
}
🙁 Nachher nicht mehr.
😁 Aber schön kurz
Wenn du die Performance Tests machst, versuchs mit längeren Arrays. 2-8 Byte sind weniger als ein Klacks, 100-1000 dürfen es schon sein, und schraub stattdessen die Durchläufe runter. Um Ausreisser zu vermeiden kann man da ruhig aucuh GC.Collect() aufrufen (aber nur für die Tests).
Siehe auchStrings performant verketten
loop:
btst #6,$bfe001
bne.s loop
rts
public static byte[] ConcateByteArrays(params byte[][] _Arrays) // 3,1 Sec
{
MemoryStream m = new MemoryStream();
m.SetLength = _Arrays.Length * _Arrays[0].Length; //Erspart dir lästiges umkopieren beim Hinzufügen.
foreach (byte[] array in _Arrays)
{
m.Write(array, 0, array.Length);
}
return m.ToArray();
}
Besser wäre wenn du aber statt einem Jagged-Array (Baum) mit mehrdimensionalen Arrays arbeitest, da die Größe eines Jagged-Arrays erst beim Durchlaufen bekannt wird.
Wie berechnest bzw. misst du die Zeiten?
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
@0815Coder
Der Test mit 12 * 1240 byte entscheidet eindeutig für deine Version. Sie ist dann drei mal schneller.
Von daher hat sich der Threat schon gelohnt. Und wenn Google zu Besuch war ist es auch zu finden.
Interessant ist, dass offensichtlich ein Array mit objects schneller an eine Methode übergeben wird als eins mit byte[].
@kleines_eichhoernchen
m.SetLength = _Arrays.Length * _Arrays[0].Length;
geht nicht, da die Arrays nicht die gleiche Größe haben.
Die Zeitvergleiche sind ja nur relativ, d.h. für meinen PC. Andere sind schneller oder langsamer.
Der Test läuft so ab:
System.Diagnostics.Stopwatch stw = new System.Diagnostics.Stopwatch();
Beginn:
int anzahlTests= 20000;
stw.Reset();
stw.Start();
// beginn Test
//-----------------------------------------------------------------
for (int i = 0; i < anzahlTests; i++)
{
byte[] uInt16231 = Umwandlungen.ConcateByteArrays(uInt1623, uInt1623, uInt1623, uInt1623, uInt1623, uInt1623, uInt1623, uInt1623, uInt1623, uInt1623, uInt1623, uInt1623);
}
//-----------------------------------------------------------------
// ende Test
stw.Stop();
double timePro = ((double)stw.ElapsedMilliseconds / (double)anzahlTests )*1000;// == 3,541 e-09 Sekunden (Dies braucht eine leere For-i-Schleife
System.Diagnostics.Debugger.Break();
goto Beginn;
Das, was in der Schleife steht ändert sich dann.
Um den Versuch zu dokumentieren habe ich mir noch etwas gebaut. Allerdings muss bei Änderungen dafür gesorgt werden, dass abgespeichert ist.
string result = "";
StreamReader sr = new StreamReader("..\\..\\Form1.cs", System.Text.Encoding.Default);
while (!sr.ReadLine().Trim().StartsWith("// beginn Test"));
string line = sr.ReadLine() + Environment.NewLine + "// " + timePro.ToString() + " Sekunden pro 1.000.000";
while (!line.Trim().StartsWith("// ende Test"))
{
if (line.Trim().StartsWith("//"))
{
line = line.Trim();
}
result += line+Environment.NewLine;
line = sr.ReadLine();
}
sr.Close();
Clipboard.SetText(result);
Gruß Robert
Ich würde zusätzlich
GC.Collect(2); //Alles ordentlich aufräumen
int startCol = GC.CollectionCount(2); //Bis zur 3. Generation
//Zeitmessung start
...
//Zeitmessung ende
int endCol = GC.CollectionCount(2);
Console.WriteLine("Anzahl der GCs: {0}", endCol - startCol);
noch einbauen, um auch die Anzahl der GC-Durchläufe miteinzubeziehen und auch darauf entsprechend zu optimieren (wenn Bedarf besteht).
Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...
Besser wäre wenn du aber statt einem Jagged-Array (Baum) mit mehrdimensionalen Arrays arbeitest, da die Größe eines Jagged-Arrays erst beim Durchlaufen bekannt wird.
Performancetechnisch ist das richtig.
aber mit params kann man keine mehrdimensionalen Arrays verwenden. ausserdem können ja auch alle arrays die er übergibt unterschiedlich lang sein.
loop:
btst #6,$bfe001
bne.s loop
rts