2010-07-28 11 views
14

Ich versuche, etwas zu bauen (letztlich ein Juwel, aber für jetzt eine Anwendung), die wie folgt funktioniert.In Ruby on Rails wie kann ich Objekte im Speicher zwischen den Sitzungen beibehalten

Angenommen zum Beispiel die DB-Datensätze sind Hunderassen. Für jede Rasse gibt es eine Elternklasse und eine Kinderklasse. Die tatsächlichen Rassen sind bis zur Laufzeit nicht bekannt.

Wenn der Server beginnt, lädt er Datensätze aus der DB und instanziiert Instanzen von Klassen basierend auf den Datensätzen, z. Ich habe vielleicht zwei Beagles und Pudel. Wenn jemand zum Server kommt, möchte er möglicherweise auf eine dieser Instanzen zugreifen.

Warum nicht einfach die Instanz im laufenden Betrieb erstellen? In meinem Fall sind die "Hunde" im Grunde Klassen, die einen Algorithmus und Daten enthalten. Der Algorithmus ändert sich nicht, die Daten ändern sich selten (in der Größenordnung von Tagen), aber auf die Ausführung des Algorithmus selbst, der sowohl Daten als auch einige dynamische Daten wie einen Zeitstempel verwendet, wird mehrmals pro Sekunde zugegriffen.

Es wäre albern, eine Instanz des Objekts neu erstellen zu müssen und die Daten jedes Mal neu laden zu müssen, nur um sie bei der nächsten Anfrage erneut auszuführen (die Anfragen ändern den Status des Objekts nicht) . Ich würde mehrere Objekte pro Sekunde erstellen und zerstören, wenn ich das gleiche Objekt einfach wiederverwenden könnte.

es macht keinen Sinn, es in der Sitzung zu behalten, da jemand, der einen Pudel will, nicht die Beagles-Informationen in seinem Sitzungsobjekt haben muss; Es ist irrelevant (und skaliert nicht).

Wie behalte ich diese Objekte im Speicher? Ich möchte grundsätzlich eine Nachschlagetabelle, um die Instanzen zu halten. In Java würde ich ein Singleton mit einer Art von hashmap oder Array erstellen, die im Speicher sitzt. In Rails habe ich das versucht, indem ich im lib-Ordner eine Singleton-Klasse erstellt habe. Ich denke - ich verstehe dieses Recht vielleicht nicht - dass die Instanz (die Tatsache, dass es ein Singleton ist, ist egal) ist verloren, wenn die Sitzung verschwindet.

Die nächste Antwort, die ich fand, war http://www.ruby-forum.com/topic/129372, die im Grunde alles in Klasse Felder und Methoden setzt. Irgendwie scheint das nicht richtig zu sein.

TIA!

Zusatz: Ich komme aus Java. In Java würde ich einfach ein Objekt erstellen, das sich auf dem Heap oder vielleicht in einer JNDI-Struktur befindet, und wenn HTTP-Anfragen eintreffen, würden sie von einem Servlet oder EJB oder einem pro-Anfrage-Objekt behandelt, das dann auf das persistente Objekt zugreifen könnte. Ich kann nicht das Äquivalent in Schienen finden.

+0

+1 für die Frage, ich habe einen Baum zum Nachschlagen Zweck. Es wird sich überhaupt nicht ändern und ich möchte es nicht bei jeder Anfrage konstruieren. – lulalala

Antwort

8

Vielleicht ist Ihr Beispiel in seiner Einfachheit verwirrend. Ich nehme an, dass Ihre Objekte ziemlich kompliziert sind und dass Ihr Benchmarking zeigt, dass es nicht sinnvoll ist, sie bei jeder Anfrage zu erstellen.

Im Produktionsmodus werden Klassen zwischen Anforderungen nicht entladen, aber Instanzen dieser Klassen sind. Die Verwendung von Klassenmitgliedern einer Klasse klingt also wie der Weg zu mir. Verwenden Sie es einfach, um Ihre Instanzen zu speichern.

class ObjectCache 
    @@objects = {:beagle => Beagle.new, :poodle => Poodle.new} 

    def lookup key 
    @@objects[key.to_sym] 
    end 
end 
+0

Danke für die Antwort. Sie haben "im Produktionsmodus" erwähnt. Ich versuche das im Entwicklungsmodus und ich verliere immer noch das Objekt zwischen den Anfragen (auch wenn die Methoden auch Klassenmethoden sind, zum Beispiel def self.lookup key), aber vielleicht liegt das an dem Modus. Ich würde mich damit zufrieden geben, jetzt zu arbeiten, aber offen gesagt fühlt sich das wirklich wie der falsche Weg an, es zu tun. – hershey

+0

Es ist nicht sehr gut definiert, was passiert, wenn Sie Instanzen von ActiveRecord-Modellen zwischen Anfragen aufbewahren, also wird dies wahrscheinlich am besten vermieden. Wenn Sie nur einfache alte Ruby-Objekte speichern, funktioniert es möglicherweise. – tadman

+0

Gute Warnung; Zum Glück sind dies nur Ruby-Objekte, keine ActiveRecord-Objekte, daher mache ich mir keine Sorgen darüber, dass der Zustand in der Datenbank verwechselt wird. Der Zustand des Objekts "Hunde" in dem obigen Beispiel ergibt sich aus einigen Daten, die von db und dem Algorithmus geladen (gelesen, nie geschrieben) wurden. Es besteht kein Risiko, dass ein Objekt mit der Datenbank inkonsistent ist, da in diesem Fall kein Objekt in der Datenbank vorhanden ist. – hershey

6

Ich würde mir keine Sorgen machen über das Laden und Verwerfen von Objekten, es sei denn, Sie können einen Benchmark erstellen, der beweist, dass es ein Problem ist. Jede Anfrage erzeugt natürlich eine außerordentliche Menge von Zwischenobjekten, und diese werden im Allgemeinen in einigen Millisekunden erstellt und zerstört.

Es ist im Allgemeinen besser, sich darauf zu konzentrieren, nur das zu laden, was erforderlich ist, die Datenbank zu normalisieren, um häufig zugreifbare Daten oder Methoden an einen geeigneten Speicherort zu verschieben oder die Ergebnisse komplizierter Berechnungen in einem Cache-Feld zu speichern.

Benchmark zuerst, nur bei Bedarf optimieren.

Das Speichern von Instanzen von Modellen in einem Klassencache funktioniert zwar, ist jedoch nur eine Option in einer Produktionsumgebung, in der die Modellklassen nicht mit jeder Anforderung neu geladen werden. Es kann Sie auch auf Fehler hinweisen, die durch veraltete Daten verursacht wurden.

Wenn Sie ein Skalierungsproblem haben, das mit diesen Methoden nicht gelöst werden kann, sollten Sie untersuchen, wie Sie einen dauerhaften Server für einen Teil Ihrer Funktionalität mithilfe einer Kombination aus Rack und EventMachine erstellen. Es gibt eine Reihe von Möglichkeiten, um einen Hintergrundprozess zu erstellen, der komplizierte Berechnungen mithilfe eines vorinstallierten Datensatzes durchführen kann. Der spezifische Ansatz hängt jedoch von verschiedenen Faktoren ab, z. B. dem Typ der Daten, mit denen Sie arbeiten und wie häufig Es wird zugegriffen.

+0

Vielen Dank, dass Sie sich die Zeit genommen haben, zu antworten. Skalierung beiseite, das scheint nur nicht wie richtige Programmierung. Das gleiche Objekt immer wieder neu zu erstellen ist vom OO-Standpunkt aus falsch, wenn das Objekt selbst wiederverwendet werden kann. Rack scheint, als ob es eine viel leichtere Version von Rails verwenden würde, ich habe nichts in der Dokumentation gesehen, was darauf hindeutet, dass es Persistenz geben kann, die Rails nicht kann. EventMachine scheint die richtige Antwort zu sein. http://www.neeraj.name/2009/12/15/ruby-eventmachine-a-short-introduction.html hat eine gute Erklärung dafür. Ich werde einen genaueren Blick darauf werfen. – hershey

+0

Die statuslose Natur von HTTP trägt oft zu Problemen wie dieser bei, wo eine Anfrage möglicherweise nichts mit der nächsten zu tun hat und ein Anwendungsframework wie Rails oft alle in der vorherigen Anfrage verwendeten Objekte säubern muss, um Platz für die Nächster. Wenn Sie eine persistente Umgebung benötigen, bauen Sie eine Engine auf, die im Hintergrund ausgeführt wird, und Sie werden massive Leistungssteigerungen feststellen, nicht nur durch Vermeidung redundanter Neuladevorgänge, sondern auch durch asynchrone Vorgänge. Einen Server zu schreiben, der das Memcache-Protokoll "spricht", ist ziemlich einfach und kann wie ein normaler Cache verwendet werden, selbst wenn er Antworten berechnet. – tadman

+0

Ich sprach zu früh. Die EventMachine bleibt nur innerhalb der Verbindung bestehen. Ich bin nicht in der Lage, eine Verbindung über Webanfragen zu bestehen, damit ich den Zustand noch verliere. Gibt es noch andere Möglichkeiten, eine Engine zu erstellen? – hershey

0

In der Produktion werden die Steuerungen und Modellklassen zwischen Abfragen nicht neu geladen, so haben Sie mehrere Möglichkeiten:

  • setzen die Objekte als Klassenvariablen in Ihrem application_controller
  • erstellen Singleton-Methoden in der Modellklassen selbst, die die Werte zurückgeben
0

Ja, Klassen können im Entwicklungsmodus auch daran gehindert werden, entladen zu werden. Es ist nicht nur eine Produktionsmodus-Sache. Dies geschieht jedoch standardmäßig im Produktionsmodus, wo Sie es manuell im Entwicklungsmodus einstellen müssen.

0

Damit Ihre Klassen auch im Entwicklungsmodus nicht bei jeder Anforderung neu geladen werden, können Sie sie außerhalb der Autoload-Pfade verschieben (wenn Sie Standardwerte außerhalb der Verzeichnisse app und lib verwenden). Auf diese Weise können Sie diese Objektklassen zwischen Anforderungen beibehalten und sie daher zum Speichern von Daten verwenden, die für jede Anforderung gleich sind.

Verwandte Themen