Jochens Weblog

ESCde Developer Blog

  Home :: Kontakt :: RSS Feed
  12 Posts :: 0 Artikel :: 4 Kommentare :: 0 Trackbacks

Archiv

Post Kategorien

ESCde

ESCde Blogger

Nach längerer Blogging-Abstinenz gibt es nun endlich mal wieder einen neuen Eintrag. Außerdem bin ich voller Hoffnung, dass ich nun wieder öfters Zeit zum Bloggen finde ;-)

Heute möchte ich das Konzept des letzten Eintrags ("Objekte rechtzeitig erzeugen") ein wenig verbessern. In diesem Eintrag ging es darum, dass viele Algorithmen ganz schnell eine große Menge von Objekten eines bestimmten Typs für ihre Berechnungen brauchen. Um so schneller diese erzeugt werden, um so schneller läuft der Algorithmus. Optimal wäre es also, wenn die Objekte bereits existieren. Genau das macht die in diesem letzten Blog-Eintrag erstellte Klasse - sie erzeugt Objekte zu einem Zeitpunkt, zu dem die dafür benötigte Rechenleistung nicht ins Gewicht fällt.

Diese Klasse hat allerdings einen Nachteil: Alle benötigten Objekte werden auf einmal erzeugt. Das heißt, dass zu irgendeinem Zeitpunkt richtig viel Rechenpower verbraucht wird. Besser wäre es, wenn die Objekte alle schön nacheinander über einen größeren Zeitraum verteilt erzeugt werden. Während des normalen Programmablaufs einer WinForms-Anwendung würde es ja nicht stören, wenn einfach ein paar mal pro Sekunde einige wenige Objekte angelegt werden. Wird dann nach 5 Minuten der Rechen- (und Speicher- ) intensive Algorithmus gestartet, sind dann auch so die nötigen Objekte bereits vorhanden.

Die unten gezeigte ObjectCreator-Klasse implementiert solch ein Verhalten. Sie bedient sich hierzu der System.Windows.Timer-Klasse, welche in einem festen Intervall eine Methode von ObjectCreator aufruft. Zu diesen Zeitpunkten werden dann einige der verwalteten Objekte erstellt:

 

class ObjectCreator<TargetType> where TargetType : class, new() { // in diesem Stack werden die Objekte gespeichert protected Stack<TargetType> mObjects = new Stack<TargetType>(); // der Timer, um regelmäßig Objekte zu erzeugen protected Timer mTimer = null; // wie viele Objekte sollen in jedem Intervall erzeugt werden? protected int mNumObjPerTick = 1; // wie viele Objekte sollen insgesamt erzeugt werden? protected int mMaxObjs = 1000; // Ermöglicht dem User, ein Maximum an verwalteten Objekten zu setzen / lesen public int MaxObjects { get { return this.mMaxObjs; } set { if (value > 0) this.mMaxObjs = value; } } // Anzahl aktuell verfügbarer Objekte public int CountCurrentObjects { get { return this.mObjects.Count; } } // Konstruktor, initialisiert den Timer public ObjectCreator() { mTimer = new Timer(); mTimer.Enabled = false; mTimer.Tick += new EventHandler(mTimer_Tick); } // ein Objekt wird erstellt und auf dem Stack abgelegt public void CreateObject() { TargetType tt = new TargetType(); mObjects.Push(tt); } // gibt ein Objekt zurück und entfernt es aus dem Stack public TargetType GetObject() { if (mObjects.Count > 0) return mObjects.Pop(); else return new TargetType(); } // aktiviert das automatischen Erzeugen von // NumObjObjekten alle MilliSecs Millisekunden public void EnableAutoCreation(int MilliSecs, int NumObj) { if (MilliSecs > 0 && NumObj > 0 && this.mObjects.Count < this.mMaxObjs) { this.mTimer.Interval = MilliSecs; this.mNumObjPerTick = NumObj; this.mTimer.Enabled = true; } } // deaktiviert die automatische Erzeugung wieder public void DisableAutoCreation() { this.mTimer.Enabled = false; } // wird vom Timer alle MilliSecs Millisekunden aufgerufen void mTimer_Tick(object sender, EventArgs e) { for (int i = 0; i < this.mNumObjPerTick; i++) { this.CreateObject(); } } }

Diese Implementierung verwendet einen Stack, um die erzeugten Objekte zwischenzuspeichern. Denkbar sind auch Ansätze mit anderen Container-Klassen, gerade auch ein Array kann sehr sinnvoll sein, da man sich bei geschickter Implementierung die Abfrage von "Count" in GetObject() sparen kann.

Die Klasse ist außerdem generisch, kann also zum frühzeitigen erzeugen aller Datentypen verwendet werden, die selbst ein Referenztyp sind und über einen Konstruktor verfügen. Ausgeschlossen sind hiervon die integralen Datentypen wie beispielsweise int, float, etc. Hierfür müßte man die Implementierung minimal abändern.

Grundsätzlich sollte man solche Klassen allerdings nur dann verwenden, wenn man wirklich viele Objekte verwendet, die auch noch eine gewisse Größe aufweisen. Bitmaps, Texturen, große Strings aber auch Klassen, die viele Membervariablen haben wären sinnvolle Beispiele. Bei der Anwendung sollte man auf jeden Fall testen, ob sich ein Geschwindigkeitsvorteil ergibt. Ist das Problem zu "gering", kann der Versuch durchaus nach hinten gehen, da der Verwaltungsaufwand nicht unerheblich ist. Bei großen Datenmengen kann man allerdings eine Geschwindigkeitssteigerung von Faktor 10 oder mehr verbuchen.

veröffentlicht am 14.02.2007 16:08

Kommentare

Bisher kein Feedback.

Kommentar abgeben

Titel:
Name:
Email:
(wird nicht angezeigt!)
Homepage:
Feedback:
Please add 4 and 8 and type the answer here: