Ich schaue mir gerade dieses Tutorial an https://www.youtube.com/watch?v=HwUnMy_pR6A und der Typ (der ziemlich kompetent zu sein scheint) verwendet ein einzelnes Array, um die Pixel seines zu rendernden zu speichern und darauf zuzugreifen Bild.
Ich habe mich gefragt, ob dies wirklich der beste Weg ist, dies zu tun. Die Alternative von Multi-Array hat zwar einen Zeiger mehr, aber Arrays haben ein O (1) für den Zugriff auf jeden Index und die Berechnung des Index in einem einzelnen Array scheint eine Addition und eine Multiplikationsoperation pro Pixel zu erfordern.
Und wenn Multi-Arrays wirklich schlecht sind, können Sie mit Hashing nicht etwas verwenden, um diese Additions- und Multiplikationsoperationen zu vermeiden?
EDIT: hier ist sein Code ...
public class Screen {
private int width, height;
public int[] pixels;
public Screen(int width, int height) {
this.width = width;
this.height = height;
// creating array the size of one index/int for every pixel
// single array has better performance than multi-array
pixels = new int[width * height];
}
public void render() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[x + y * width] = 0xff00ff;
}
}
}
}
Antworten:
Es ist immer schwierig, über die "beste Wahl" zu sprechen, solange Sie die Aufgabe , die Sie ausführen möchten, nicht im Detail angegeben haben.
Hier sind jedoch einige Aspekte zu berücksichtigen. Zuallererst: Java ist nicht C. Die Speicherverwaltung ist völlig anders, daher muss man sehr vorsichtig sein, wenn man versucht, Erkenntnisse aus einer Programmierumgebung auf eine andere anzuwenden.
Zum Beispiel Ihre Aussage:
Wie bereits in einer der verknüpften Antworten ausgeführt: Ein "2D-Array" in C ist hauptsächlich eine syntaktische Annehmlichkeit für die Adressierung eines einzelnen (1D) Speicherblocks. Also wenn du so etwas schreibst
in C könnte dies tatsächlich äquivalent zu sein
Das Argument, eine Multiplikation zu speichern, ist hier also zumindest fraglich. Ein Sonderfall ist hier, wenn Sie tatsächlich ein Array von Zeigern haben , denen jede Zeile manuell zugewiesen wird
malloc
. Dann ist das Adressierungsschema anders (und tatsächlich kann dies als näher an dem angesehen werden, was Java tut).Darüber hinaus ist Java eine Sprache mit einem Just-In-Time-Compiler, was Vergleiche auf der Ebene einzelner Anweisungen (wie Multiplikationen) sehr schwierig macht. Sie wissen kaum, was die JIT mit Ihrem Code macht. Aber auf jeden Fall können Sie davon ausgehen, dass es schneller wird, und die schlimmsten Tricks anwenden, die Sie sich (nicht) vorstellen können.
In Bezug auf die allgemeine Strategie, ein 1D-Array für Pixel zu verwenden, gibt es einen Grund, dies in Java zu tun (und da das verknüpfte Video schnell überflogen wird, scheint dieser Grund hier zuzutreffen): Ein 1D-Array kann bequem in ein übertragen werden
BufferedImage
.Dies ist ein Grund aus der Sicht der "Bequemlichkeit". Aber wenn es um Leistung geht , gibt es andere Aspekte, die weitaus wichtiger sind als ein paar Multiplikationen. Die ersten, die mir in den Sinn kommen, sind
Zwei Beispiele zeigen, wie sie die Leistung beeinflussen können:
Cache-Effekte
Für das erste Beispiel können Sie das folgende Beispiel betrachten: Es zeigt den signifikanten Leistungsunterschied zwischen dem Zugriff auf Pixel mit
und mit
In einem kleinen Testprogramm zusammengefasst:
Die Details variieren und hängen stark vom Zielsystem (und seiner Cache-Größe) ab. Dies ist also KEIN "Benchmark", zeigt jedoch, dass es möglicherweise einen großen Unterschied gibt. Auf meinem System kann eine Größenordnung, z.
Der zweite Einfluss kann noch schwieriger sein:
Implementierungsdetails
Die Java-
BufferedImage
Klasse ist sehr praktisch, und Operationen mit dieser Klasse können unglaublich schnell sein.Die erste Bedingung hierfür ist, dass der Bildtyp für das Zielsystem "geeignet" sein muss. Insbesondere bin ich noch nie auf ein System gestoßen, bei dem
BuferedImage
die vonint[]
Arrays unterstützten Typen nicht die schnellsten waren. Das bedeutet, dass Sie immer sicherstellen sollten, dass Sie Bilder des TypsTYPE_INT_ARGB
oder verwendenTYPE_INT_RGB
.Die zweite Bedingung ist subtiler. Die Ingenieure von Sun / Oracle setzten einige böse Tricks ein, um das Malen
BufferedImages
so schnell wie möglich zu gestalten. Eine dieser Optimierungen besteht darin, dass sie erkennen, ob das Image vollständig im VRAM gespeichert werden kann oder ob sie das Image mit dem Inhalt eines Arrays synchronisieren müssen, das sich in der Java-Welt befindet. Ein Bild, das im VRAM gespeichert werden kann, wird als "verwaltetes" Bild bezeichnet. Und es gibt einige Operationen, die die "Verwaltbarkeit" eines Bildes zerstören . Eine dieser Operationen besteht darin, dasDataBuffer
ausRaster
dem Bild zu erhalten.Wieder ein Programm, in dem ich versucht habe, den Effekt zu demonstrieren. Es werden zwei
BufferedImage
Instanzen erstellt. Bei einem von ihnen erhält es dasDataBuffer
und bei dem anderen nicht. Beachten Sie, dass dies auch KEIN "Benchmark" ist und mit einem großen Salzkorn eingenommen werden sollte . Es zeigt sich jedoch, dass das Erhalten desDataBuffer
Bilds die Malleistung erheblich verringern kann.Die tatsächlichen Auswirkungen werden hier wahrscheinlich noch stärker von der Hardware (und der VM-Version!) Abhängen, aber von meinem System wird gedruckt
Dies bedeutet, dass das Erhalten des
DataBuffer
von aBufferedImage
das Bild um einen Faktor von mehr als 100 verlangsamen kann .(Nebenbei: Um diese Verlangsamung zu vermeiden, kann man die
setRGB
Methode wie in verwendenDazu gehört natürlich auch das Kopieren. Am Ende gibt es also einen Kompromiss zwischen der Geschwindigkeit der Manipulation der Pixel und der Geschwindigkeit des Malens des Bildes.
quelle
In meiner Erfahrung mit Java-Arrays habe ich durch die Verwendung eines 1D-Arrays erhebliche Geschwindigkeitsverbesserungen festgestellt. Ihre Ergebnisse können variieren, daher ist es wichtig, dass Sie selbst Tests durchführen.
Bedenken Sie, dass Ihre primäre Verwendung dieses Arrays im Wesentlichen auf die gleiche Weise erfolgt, wie die Daten im RAM gespeichert werden. Dies macht die Speicherzuordnung eines 1D-Arrays vorteilhafter. Für ein mehrdimensionales Array sind ebenfalls Indexierungsberechnungen erforderlich. Sie werden nur hinter den Kulissen durchgeführt.
Mit der richtigen Abstraktionsebene können Sie problemlos zwischen den beiden Methoden wechseln und einige eigene Leistungstests durchführen.
quelle