Hallo!
Ich verwende ein selbst geschriebenes Java-Programm um eine Monte-Carlo-Simulation durchzuführen. Ohne jetzt ins Detail gehen zu wollen, geht es dabei um Folgendes: Es wird die Entwicklung eines System konstanter Größe N (Größenordnung einige tausend bis einstelliger Millionenbereich) simuliert. Es werden pro Simulation 100.000 Simulationsschritte durchgeführt, wobei sich ein Simulationsschritt auf ein durchgeführtes Ereignis pro Objekt im System (also N Ereignisse) bezieht. Vor jedem Ereignis wird mit konstanten Wahrscheinlichkeiten ausgewählt, welche Art von Ereignis durchgeführt werden soll, denn es existieren prinzipiell verschiedene Ereignisse. Diese haben aber alle gemeinsam, dass sie eines oder zwei Objekte des Systems auswählen und anhand des Aktuellen Zustands des Systems die Eigenschaften des ausgewählten Objekts verändern. Ich habe diese Simulation in mehreren Versionen implementiert und dabei festgestellt, dass die Simulation gleicher Systeme in den unterschiedlichen Implementierungen jeweils unterschiedlich lange braucht. Folgende Versionen habe ich implementiert:
- Eine "Basic-Version", die nicht flexibel angepasst werden kann, also nur genau eine Art von System simulieren kann, dadurch konnte ich mir jegliche Vererbungen etc. sparen. Ich habe hier keinerlei Getter/Setter verwendet, sondern einfach alle Felder als public deklariert.
- Eine Version, welche zwar nicht wesentlich flexibler ist, aber die Style(?)-Vorgaben befolgte, also beispielsweise Getter/Setter
- Eine flexible Version, hier wurde viel mit Vererbung gearbeitet, es sind neue Arten von Systemen definierbar, sowie neue Ereignisse, etc.
Nun ist diese flexible Version leider am unperformantesten. Prinzipiell sind die Unterschiede hier nicht extrem, aber der benötigte Zeitaufwand wächst mit Systemgröße linear und bei den "großen" Systemen mit einer Größe macht dann ein Faktor 4-5 schon einen Unterschied, wenn statt 24h eben 5 Tage benötigt werden. Nun kann mit den Angaben die ich hier bisher gemacht habe vermutlich noch keine Diagnose gestellt werden, deshalb wollte ich nachfragen, ob ihr allgemeine Tipps habt, auf was ich bei einer solchen Art von Simulation achten sollte. Wenn ihr gute Beiträge, Webseiten, etc. dazu kennt nehme ich das alles gerne! Ich bin aber euch mehr Anfänger, deshalb fehlt mir eben auch der Blick "hinter die Kulissen".
Damit vielleicht noch spezifischere Tipps gegeben werden können hier nochmal ein paar weitere Infos, ich erkläre es mal recht abstrakt, weil es sonst vielleicht noch komplizierter wird:
Jedes Ereignis kann angenommen oder abgelehnt werden. Dafür wird das Ereignis durchgeführt (Details dazu gleich) und anschließend eine Wahrscheinlichkeit berechnet dieses Ereignis anzunehmen oder abzulehnen, die entsprechende Wahrscheinlichkeit wird mit java.lang.Math.exp berechnet, das Argument der Funktion wird berechnet aus dem Zustand des Systems vor der Durchführung des Ereignissen und dem Zustand danach. Wird das Ereignis abgelehnt, dann wird das bereits durchgeführte Ereignis einfach wieder rückgängig gemacht (alle geänderten Variablen auf ihren Ausgangszustand gesetzt).
Nun zu den Ereignissen: Für jedes Ereignis existiert eine eigene Klasse, die von der Klasse AbstraktesEreignis erbt. In der abstrakten Klasse wird nur die Methode zur Berechnung der Wahrscheinlichkeit implementiert. Jedes Ereignis besitzt eine Methode perform() zur Durchführung. Es existiert zusätzlich eine Klasse, die sich um die Verwaltung der Ereignisse kümmert: Hier werden jeweils Objekte der Ereignisse gespeichert und hier erfolgt die Auswahl eines Ereignisses anhand der Ziehung der Zufallszahlen. Die Ereignisse verändern jeweils die Objekte des Systems, dafür besitzen sie entweder eine Referenz zum Array der Objekte (welcher ursprünglich der System-Klasse ist) oder eine eigene Version davon, in dem beispielsweise die Ereignisse nach einer bestimmten Eigenschaft der Objekte sortiert vorliegen.
Nun ist der Vorgang einfach folgender, dass jedes Mal im EreignisManager ein zufälliges Ereignis ausgewählt wird, es wird dessen perform()-Methode aufgerufen und in der Perform-Methode wird dann das Ereignis angenommen oder abgelehnt. In den Perform-Methoden werden dann beispielsweise auch noch weitere Zufallszahlen gezogen, es werden ArrayLists erstellt, Schleifen durchlaufen, if-Bedingungen geprüft, etc.
Und dazu noch eine etwas konkretere Frage: Ich verwende Beispielsweise ArrayLists, weil ich Objekte "sammeln" muss, die eine bestimmte Eigenschaft besitzen. Da mache ich mithilfe einer for-Schleife, in der mithilfe einer if-Bedingung einfach gefragt wird, ob die Eigenschaft erfüllt wird. Nun ist es eben so dass dadurch die Länge der ArrayList variieren kann, weshalb ich auch keinen Array verwende. Allerdings kann die Länge höchstens einen (konstanten) Maximalwert annehemen. Ist es dann beispielsweise performanter, einen Array zu erstellen, der Länge dieses Maximalwerts und dann später beim iterieren über diesen jeweils zu überprüfen ob das jeweilige Objekt null ist und dann die Schleife zu beenden?
Ich hoffe das alles gut verständlich ist und ich die wichtigsten Infos genannt habe. Ich würde mich sehr sowohl über allgemeine, als auch spezifische Tipps freuen und kann gerne weitere Infos geben, falls benötigt.
Viele Grüße und schonmal herzlichen Dank!
Ich verwende ein selbst geschriebenes Java-Programm um eine Monte-Carlo-Simulation durchzuführen. Ohne jetzt ins Detail gehen zu wollen, geht es dabei um Folgendes: Es wird die Entwicklung eines System konstanter Größe N (Größenordnung einige tausend bis einstelliger Millionenbereich) simuliert. Es werden pro Simulation 100.000 Simulationsschritte durchgeführt, wobei sich ein Simulationsschritt auf ein durchgeführtes Ereignis pro Objekt im System (also N Ereignisse) bezieht. Vor jedem Ereignis wird mit konstanten Wahrscheinlichkeiten ausgewählt, welche Art von Ereignis durchgeführt werden soll, denn es existieren prinzipiell verschiedene Ereignisse. Diese haben aber alle gemeinsam, dass sie eines oder zwei Objekte des Systems auswählen und anhand des Aktuellen Zustands des Systems die Eigenschaften des ausgewählten Objekts verändern. Ich habe diese Simulation in mehreren Versionen implementiert und dabei festgestellt, dass die Simulation gleicher Systeme in den unterschiedlichen Implementierungen jeweils unterschiedlich lange braucht. Folgende Versionen habe ich implementiert:
- Eine "Basic-Version", die nicht flexibel angepasst werden kann, also nur genau eine Art von System simulieren kann, dadurch konnte ich mir jegliche Vererbungen etc. sparen. Ich habe hier keinerlei Getter/Setter verwendet, sondern einfach alle Felder als public deklariert.
- Eine Version, welche zwar nicht wesentlich flexibler ist, aber die Style(?)-Vorgaben befolgte, also beispielsweise Getter/Setter
- Eine flexible Version, hier wurde viel mit Vererbung gearbeitet, es sind neue Arten von Systemen definierbar, sowie neue Ereignisse, etc.
Nun ist diese flexible Version leider am unperformantesten. Prinzipiell sind die Unterschiede hier nicht extrem, aber der benötigte Zeitaufwand wächst mit Systemgröße linear und bei den "großen" Systemen mit einer Größe macht dann ein Faktor 4-5 schon einen Unterschied, wenn statt 24h eben 5 Tage benötigt werden. Nun kann mit den Angaben die ich hier bisher gemacht habe vermutlich noch keine Diagnose gestellt werden, deshalb wollte ich nachfragen, ob ihr allgemeine Tipps habt, auf was ich bei einer solchen Art von Simulation achten sollte. Wenn ihr gute Beiträge, Webseiten, etc. dazu kennt nehme ich das alles gerne! Ich bin aber euch mehr Anfänger, deshalb fehlt mir eben auch der Blick "hinter die Kulissen".
Damit vielleicht noch spezifischere Tipps gegeben werden können hier nochmal ein paar weitere Infos, ich erkläre es mal recht abstrakt, weil es sonst vielleicht noch komplizierter wird:
Jedes Ereignis kann angenommen oder abgelehnt werden. Dafür wird das Ereignis durchgeführt (Details dazu gleich) und anschließend eine Wahrscheinlichkeit berechnet dieses Ereignis anzunehmen oder abzulehnen, die entsprechende Wahrscheinlichkeit wird mit java.lang.Math.exp berechnet, das Argument der Funktion wird berechnet aus dem Zustand des Systems vor der Durchführung des Ereignissen und dem Zustand danach. Wird das Ereignis abgelehnt, dann wird das bereits durchgeführte Ereignis einfach wieder rückgängig gemacht (alle geänderten Variablen auf ihren Ausgangszustand gesetzt).
Nun zu den Ereignissen: Für jedes Ereignis existiert eine eigene Klasse, die von der Klasse AbstraktesEreignis erbt. In der abstrakten Klasse wird nur die Methode zur Berechnung der Wahrscheinlichkeit implementiert. Jedes Ereignis besitzt eine Methode perform() zur Durchführung. Es existiert zusätzlich eine Klasse, die sich um die Verwaltung der Ereignisse kümmert: Hier werden jeweils Objekte der Ereignisse gespeichert und hier erfolgt die Auswahl eines Ereignisses anhand der Ziehung der Zufallszahlen. Die Ereignisse verändern jeweils die Objekte des Systems, dafür besitzen sie entweder eine Referenz zum Array der Objekte (welcher ursprünglich der System-Klasse ist) oder eine eigene Version davon, in dem beispielsweise die Ereignisse nach einer bestimmten Eigenschaft der Objekte sortiert vorliegen.
Nun ist der Vorgang einfach folgender, dass jedes Mal im EreignisManager ein zufälliges Ereignis ausgewählt wird, es wird dessen perform()-Methode aufgerufen und in der Perform-Methode wird dann das Ereignis angenommen oder abgelehnt. In den Perform-Methoden werden dann beispielsweise auch noch weitere Zufallszahlen gezogen, es werden ArrayLists erstellt, Schleifen durchlaufen, if-Bedingungen geprüft, etc.
Und dazu noch eine etwas konkretere Frage: Ich verwende Beispielsweise ArrayLists, weil ich Objekte "sammeln" muss, die eine bestimmte Eigenschaft besitzen. Da mache ich mithilfe einer for-Schleife, in der mithilfe einer if-Bedingung einfach gefragt wird, ob die Eigenschaft erfüllt wird. Nun ist es eben so dass dadurch die Länge der ArrayList variieren kann, weshalb ich auch keinen Array verwende. Allerdings kann die Länge höchstens einen (konstanten) Maximalwert annehemen. Ist es dann beispielsweise performanter, einen Array zu erstellen, der Länge dieses Maximalwerts und dann später beim iterieren über diesen jeweils zu überprüfen ob das jeweilige Objekt null ist und dann die Schleife zu beenden?
Ich hoffe das alles gut verständlich ist und ich die wichtigsten Infos genannt habe. Ich würde mich sehr sowohl über allgemeine, als auch spezifische Tipps freuen und kann gerne weitere Infos geben, falls benötigt.
Viele Grüße und schonmal herzlichen Dank!