Manuelle Indizierung über gezackte Arrays?

8

Ich bin an einem Leistungsengpass in meinem Programm, wo ich millionenfach auf Elemente aus einem Array in einer engen Schleife zugreifen muss.

Ich schaute mich um und der allgemeine Konsens scheint zu sein, dass obwohl mehrdimensionale Arrays schneller sein sollten, ihre zugrundeliegende Implementierung ineffizient ist, verwenden Sie stattdessen einfach gezackte Arrays. Ich habe es profiliert und natürlich sind gezackte Arrays 50% schneller. Gut.

Ich habe jedoch auch versucht, manuell zu indizieren (wie in, indem ich das Verhalten eines mehrdimensionalen Arrays simuliere, indem ich einfach so etwas tue: object value = array[i * 24 + j]; (where 24 is an array size) und durch Multiplikation mit einem einzelnen Dimensions-Array darauf zugreife, multidimensionale Arrays zu simulieren) / p>

Überraschenderweise war dies auch schneller als ein gezacktes Array um etwa 15% für Zugriffe (alles was mir wichtig ist). Das macht mich traurig, weil es zum einen albern erscheint, dass das manuelle Erstellen mehrdimensionaler Arrays viel schneller ist als die eingebaute Implementierung von C # und zweitens die Mathematik, die benötigt wird, um Indices zu erhalten, im Vergleich zur Indexierung mit gezackten / mehrdimensionalen Arrays hässlicher ist >

Gibt es etwas, das ich tun kann, um die Geschwindigkeitsvorteile zurückzugewinnen, ohne meine eigene manuelle Indexierung verwenden zu müssen? Sicherlich gibt es eine Art von Optimierung, die eingestellt oder überprüft werden kann, um dieses Verhalten zu simulieren? Warum ist die C # -Implementierung von Arrays so ineffizient?

    
John Smith 12.03.2015, 15:25
quelle

1 Antwort

5
  

Überraschenderweise war dies auch schneller als ein gezacktes Array um etwa 15% für Zugriffe

Das sollte überhaupt nicht überraschen, denn die Indizierung eines gezackten Arrays erfordert eine zusätzliche Dereferenzierung. Wenn Sie a[i][j] schreiben, muss der Computer Folgendes tun:

  • Berechne die Position des verschachtelten Arrays i im gezackten Array a
  • Holen Sie den Speicherort des verschachtelten Arrays a[i] (erste Dereferenzierung)
  • Berechne die Position des Elements j in a[i]
  • Holen Sie den Wert an der Stelle j von a[i] (zweite Dereferenzierung)

Wenn Sie ein 2D-Array in einem Vektor falten, führt der Computer nur eine Dereferenzierung durch:

  • Berechne die Position des Zielelements
  • Hol den Wert aus dem Array (die einzige Dereferenzierung)

Im Wesentlichen handeln Sie eine Dereferenz für eine Multiplikation; Multiplikation ist billiger.

Außerdem erhalten Sie die Kontinuität von Elementen im Speicher - etwas, das Sie mit einem gezackten Array nicht garantieren können. Dies wird wichtig für Code, der auf Cachetreffer reagiert.

  

Gibt es etwas, was ich tun kann, um die Geschwindigkeitsvorteile zurückzugewinnen, ohne meine eigene manuelle Indizierung verwenden zu müssen?

Das Verwenden Ihres Indexierungsschemas ist ein Weg zu gehen. Sie können es vor Betrachtern Ihres Codes verbergen, indem Sie eine Klasse erstellen, z. B. Matrix2D , die ein operator [] ausgibt, das zwei Indizes benötigt, und den Wert erzeugt. Auf diese Weise würde der Code, der den Offset berechnet, den Lesern Ihres Programms verborgen bleiben, da der a[i * 24 + j] -Teil wie a[i, j]

aussehen würde     
dasblinkenlight 12.03.2015, 15:35
quelle