C# - Mi 02.03.16 22:07
Titel: Pointer in C# - Felder die auf Felder zeigen
Hey Leute,
ich versuche gerade sehr schnelle Farbstrukturen zu erstellen. Ich habe bisher drei eigene Color-Strukturen erstellt die alle schnellere Zugriffe erlauben als die System.Drawing.Color-Struktur.
Meine Performanceanalyse arbeitet wie folgt:
Je 10 Millionen Aufrufe:
1. Initialisiere die eine Variable des entsprechenden Typs mittles
new ColorXY(r, g, b)
2. Überschreibe den roten Kanal
3. Überschreibe den grünen Kanal
4. Überschreibe den blauen Kanal
5. Lade den ARGB-Wert in einen lokale Integer Variable
6. Ändere die Integer Variable
7. Schreibe den geänderten Integerwert zurück in die Color-Struktur
Das erste Problem hier ist, dass ich die System.Drawing.Color-Struktur nicht verändern kann und daher in jeder Zeile der Analyse die Struktur komplett neu initialisieren muss...
Jedenfalls ergibt sich nach mehreren Durchläufen folgendes Ergebnis:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51:
| Performance analysis on Color structures
System.Drawing.Color Struct: 1029,169000ms Color1 Struct: 759,546800ms Color2 Struct: 486,970600ms Color3 Struct: 596,709200ms
System.Drawing.Color Struct: 954,173400ms Color1 Struct: 760,178700ms Color2 Struct: 483,463700ms Color3 Struct: 597,622000ms
System.Drawing.Color Struct: 953,712500ms Color1 Struct: 761,958900ms Color2 Struct: 485,843000ms Color3 Struct: 598,601800ms
System.Drawing.Color Struct: 953,704000ms Color1 Struct: 759,919700ms Color2 Struct: 482,397500ms Color3 Struct: 598,858800ms
System.Drawing.Color Struct: 951,736500ms Color1 Struct: 762,630900ms Color2 Struct: 483,027300ms Color3 Struct: 599,863700ms
System.Drawing.Color Struct: 954,577600ms Color1 Struct: 758,925000ms Color2 Struct: 484,936300ms Color3 Struct: 597,930200ms
System.Drawing.Color Struct: 951,582500ms Color1 Struct: 757,759900ms Color2 Struct: 482,331100ms Color3 Struct: 597,216700ms
System.Drawing.Color Struct: 954,226100ms Color1 Struct: 760,384100ms Color2 Struct: 485,471900ms Color3 Struct: 597,050100ms
System.Drawing.Color Struct: 951,759000ms Color1 Struct: 764,923800ms Color2 Struct: 480,794400ms Color3 Struct: 602,168100ms
System.Drawing.Color Struct: 954,407300ms Color1 Struct: 759,317700ms Color2 Struct: 488,296300ms Color3 Struct: 594,308500ms |
Color2 und Color3 sind unsafe Code (Quellcode steht am Ende).
Ich möchte jetzt noch eine weitere Methode testen, jedoch weiß ich nicht wie ich den Code dafür schreibe.
Color4 soll so ähnlich aussehen wie Color2, aber ich würde gerne eine öffentliche Integer Variable anlegen, die den ARGB-Wert hält. Die Felder A, R, G, B (also die einzelnen Farbkanäle) sollen dann Byte-Pointer auf das ARGB Feld sein. Ich kann jedoch keine Pointer außerhalb von
fixed-Blöcken verwenden. Da durch das Memmory Management mein ARGB Feld im Speicher rumwandern kann, wäre ein Pointer auf die Addresse relativ sinnfrei.
Es gibt jedoch die Möglichkeit Arrays fest anzupinnen (auch als Klassenvariable) via
C#-Quelltext
1:
| private fixed byte data[4] |
Diese Syntax erinnert mich stark an C und weniger an C#.
Das Array müsste doch jetzt im Speicher angepinnt sein, sodass der Manager es nicht mehr verschiebt, richtig?
Aber wie zur Hölle verwende ich das Array? Ich kann in keiner Weise darauf zugreifen oder es ändern, geschweige denn Pointer darauf zeigen lassen. Egal in welchem Kontext ich das Array verwenden möchte, ich erhalte immer diese Fehlermeldung (auch in fixed-Blöcken):
Zitat: |
Fehler CS1666 Sie können keine Puffer fester Größe verwenden, die in nicht festen Ausdrücken enthalten sind. Verwenden Sie die fixed-Anweisung.
|
Weiß jemand wie ich dieses Problem lösen kann, bzw ob es überhaupt so funktionieren kann? Ich bin auch offen für andere Methoden die geringe Zugriffszeiten ermöglichen.
Das Ganze hat natürlich einen Grund. Ich steige gerade ins Gebiet der Bildverarbeitung (sprich -bearbeitung und -analyse) ein und möchte natürlich die Performance etwas hochschrauben. Das C# und Managed Code nicht die beste Lösung ist, ist mir klar. Aber ich möchte zuerst mal die Grundlagen verstehen und anwenden können, ohne mich mit einer "fremden" Programmiersprache rumzuschlagen. Ich möchte auch keine Bibliotheken (AForge & Co) verwenden, da es mir um die Funktionsweise der Algorithmen und Abläufen geht.
Vielen Dank für eure Hilfe.
Die wichtigsten Codeausschnitte:
Analyse-Kern:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++) { color2 = new Color2(100, 150, 200); color2.R = 0x10; color2.G = 0x20; color2.B = 0x30; int argb = color2.ARGB; argb &= 0x0FFFFFFF; color2.ARGB = argb; } watch.Stop(); |
Color1:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
| public struct RGBColor { public uint ARGB { get { return (uint)((A << 24) | (R << 16) | (G << 8) | B); } set { A = (byte) (value >> 24); R = (byte) ((value >> 16) & 0xFF); G = (byte) ((value >> 8) & 0xFF); B = (byte) (value & 0xFF); } }
public byte A { get; set; } public byte R { get; set; } public byte G { get; set; } public byte B { get; set; }
public RGBColor(byte a, byte r, byte g, byte b) { A = a; R = r; G = g; B = b; }
public RGBColor(byte r, byte g, byte b) : this(255, r, g, b) { }
public RGBColor(int argb) : this((uint) argb) {
}
public RGBColor(uint argb) : this((byte)(argb >> 24), (byte)((argb >> 16) & 0xFF), (byte)((argb >> 8) & 0xFF), (byte)(argb & 0xFF)) {
} } |
Color2
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70:
| unsafe struct Color2 { private byte[] argb;
public int ARGB { get { fixed (byte* ptr = &argb[0]) return *ptr; } set { fixed (byte* ptr = &argb[0]) { int* i = (int*) ptr; *i = value; } } }
public byte A { get { return argb[0]; } set { argb[0] = value; } }
public byte R { get { return argb[1]; } set { argb[1] = value; } }
public byte G { get { return argb[2]; } set { argb[2] = value; } }
public byte B { get { return argb[3]; } set { argb[3] = value; } }
public Color2(byte a, byte r, byte g, byte b) { argb = new[] {a, r, g, b}; } public Color2(byte r, byte g, byte b) : this(255, r, g, b) {
}
public Color2(int argb) : this((uint) argb) {
}
public Color2(uint argb) { this.argb = new byte[4];
unchecked { ARGB = (int)argb; } }
} |
Color3
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114:
| unsafe struct Color3 { public int ARGB; public byte A { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*) ptr; return *ptr2; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; *ptr2 = value; } } }
public byte R { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; return ptr2[1]; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; ptr2[1] = value; } } }
public byte G { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; return ptr2[2]; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; ptr2[2] = value; } } }
public byte B { get { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; return ptr2[3]; } } set { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*)ptr; ptr2[3] = value; } } }
public Color3(byte a, byte r, byte g, byte b) { fixed (int* ptr = &ARGB) { byte* ptr2 = (byte*) ptr; *ptr2++ = a; *ptr2++ = r; *ptr2++ = g; *ptr2 = b; } }
public Color3(byte r, byte g, byte b) : this(255, r, g, b) {
}
public Color3(int argb) { ARGB = argb; }
public Color3(uint argb) { unchecked { ARGB = (int)argb; } } } |