2008-10-14 8 views
27

Ich arbeite an einem Projekt in C#. Der vorherige Programmierer kannte die objektorientierte Programmierung nicht, daher ist der meiste Code in riesigen Dateien (wir sprechen über 4-5000 Zeilen) verteilt über Zehner und manchmal Hunderte von Methoden, aber nur eine Klasse. Ein solches Projekt zu reformieren, ist ein gewaltiges Unterfangen, und so habe ich jetzt halb gelernt, damit zu leben.Leistung der Verwendung von statischen Methoden vs. Instanziierung der Klasse mit den Methoden

Wenn eine Methode in einer der Codedateien verwendet wird, wird die Klasse instanziiert und anschließend die Methode für die Objektinstanz aufgerufen.

Ich frage mich, ob es spürbare Leistungseinbußen gibt, wenn man es so macht? Sollte ich alle Methoden "vorerst" statisch machen und, was am wichtigsten ist, wird die Anwendung in irgendeiner Weise davon profitieren?

+0

Ich denke, das sollte –

Antwort

24

Von here ist ein statischer Aufruf 4- bis 5-mal schneller als das Erstellen einer Instanz bei jedem Aufruf einer Instanzmethode. Wir sprechen jedoch immer noch nur über einige zehn Nanosekunden pro Aufruf, so dass Sie kaum einen Nutzen bemerken, es sei denn, Sie haben sehr enge Schleifen, die eine Methode Millionen Mal aufrufen, und Sie könnten den gleichen Nutzen erzielen, indem Sie eine einzelne Instanz außerhalb erstellen diese Schleife und wiederverwenden.

Da Sie jede Aufruf-Site ändern müssen, um die neue statische Methode zu verwenden, werden Sie wahrscheinlich besser Zeit mit dem Refactoring verbringen.

+0

Ehrfürchtig Artikel CS.SE migriert werden. Ich fing gerade damit an, weil ich daran interessiert war, was schneller ist. "While object.read" oder For-Loop und IF. Und dieser Artikel ist nach meiner persönlichen Recherche genau das Richtige. Sehr schön. Jetzt habe ich ein sehr großes Objekt, auf das an vielen Stellen zugegriffen wird, und ich fragte mich, ob es sich lohnt, es methodisch an den Ort zu übergeben, an den es gehen soll, oder einfach eine globale Variablenklasse zu erstellen und darauf zuzugreifen. Schwer zu testen, was schneller sein wird ...? :( –

2

Es scheint mir albern, ein Objekt zu erstellen, nur damit Sie eine Methode aufrufen können, die scheinbar keine Nebenwirkungen auf das Objekt hat (aus Ihrer Beschreibung nehme ich das an). Es scheint mir, dass ein besserer Kompromiss wäre, mehrere globale Objekte zu haben und diese einfach zu verwenden. Auf diese Weise können Sie die Variablen, die normalerweise global sind, in die entsprechenden Klassen einfügen, so dass sie einen etwas kleineren Bereich haben.

Von dort aus können Sie den Bereich dieser Objekte langsam verkleinern, bis Sie ein anständiges OOP-Design haben.

Dann wiederum wäre der Ansatz, den I wahrscheinlich verwenden würde, anders;).

Persönlich würde ich wahrscheinlich auf Strukturen und die Funktionen, die auf ihnen arbeiten konzentrieren und versuchen, diese in Klassen mit Mitgliedern Stück für Stück zu konvertieren.

Für den Leistungsaspekt der Frage sollten statische Methoden etwas schneller sein (aber nicht viel), da sie kein Konstruieren, Übergeben und Dekonstruieren eines Objekts beinhalten.

3

Ich denke, Sie haben diese Frage teilweise so beantwortet, wie Sie es gefragt haben: Gibt es irgendwelche spürbare Leistungsstrafen in dem Code, den Sie haben?

Wenn die Strafen nicht bemerkbar sind, müssen Sie überhaupt nichts tun. (Obwohl es selbstverständlich ist, würde die Codebasis von einem graduellen Refactor zu einem respektablen OO-Modell dramatisch profitieren).

Ich denke, was ich sage ist, ein Leistungsproblem ist nur ein Problem, wenn Sie feststellen, dass es ein Problem ist.

7

Es hängt davon ab, was dieses Objekt noch enthält - wenn das "Objekt" nur ein Bündel von Funktionen ist, dann ist es wahrscheinlich nicht das Ende der Welt. Wenn das Objekt jedoch eine Menge anderer Objekte enthält, ruft das Instanziieren alle Konstruktoren (und Destruktoren, wenn es gelöscht wird) auf, und Sie erhalten möglicherweise eine Speicherfragmentierung und so weiter.

Das heißt, es klingt nicht wie Leistung ist Ihr größtes Problem jetzt.

9

Ich habe mit einem ähnlichen Problem, wo ich arbeite behandelt. Der Programmierer vor mir hat 1 Controller-Klasse erstellt, in der alle BLL-Funktionen abgelegt wurden.

Wir entwickeln das System jetzt neu und haben viele Controller-Klassen erstellt, je nachdem, was sie steuern sollen, z.

Usercontroller, GeographyController, ShoppingController ...

Innerhalb jeder Controller-Klasse sie statische Methoden haben, die Anrufe cachen oder die DAL das Singleton Muster.

Dies hat uns zwei Hauptvorteile gegeben. Es ist etwas schneller (etwa 2-3 mal schneller, aber wir sprachen hier Nanosekunden; P). Die andere ist, dass der Code viel sauberer ist

dh

ShoppingController.ListPaymentMethods() 

statt

new ShoppingController().ListPaymentMethods() 

Ich denke, dass es sinnvoll, statische Methoden oder Klassen zu verwenden macht, wenn die Klasse halten keinen Staat .

5

Sie müssen die Ziele des Neuschreibens bestimmen. Wenn Sie einen überprüfbaren, erweiterbaren & wartbaren OO-Code haben möchten, könnten Sie versuchen, Objekte und ihre Instanzmethoden zu verwenden. Nach all dem ist objektorientiertes Programmieren gemeint, nicht klassenorientierte Programmierung.

Es ist sehr einfach, Objekte zu fälschen und/oder zu spiegeln, wenn Sie Klassen definieren, die Schnittstellen implementieren und Instanzmethoden ausführen. Dies macht ein gründliches Testen von Einheiten schnell und effektiv.

Wenn Sie gute OO-Prinzipien befolgen (siehe SOLID unter http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29) und/oder Design-Patterns verwenden, werden Sie sicherlich eine Vielzahl von instanzbasierten, schnittstellenbasierten Entwicklungen durchführen und nicht viele statische Methoden verwenden.

Wie für diesen Vorschlag:

Es scheint mir dumm ein Objekt GERADE zu erstellen, so dass Sie eine Methode aufrufen kann, die scheinbar keine Nebenwirkungen auf das Objekt hat (aus Ihrer Beschreibung Ich gehe davon aus das).

sehe ich eine Menge in dot net Geschäften und mir diese verletzt Kapselung, ein Schlüssel OO-Konzept. Ich sollte nicht in der Lage sein zu sagen, ob eine Methode Nebenwirkungen hat, ob die Methode statisch ist oder nicht. Abgesehen von der Kapselung bedeutet dies, dass Sie die Methoden von static in instance ändern müssen, wenn Sie sie modifizieren, um Nebenwirkungen zu haben. Ich schlage vor, Sie lesen das Open/Closed-Prinzip für dieses Thema und sehen, wie der vorgeschlagene Ansatz, der oben zitiert wurde, in diesem Sinne funktioniert.

Denken Sie daran, dass alte Kastanie, "vorzeitige Optimierung ist die Wurzel allen Übels". Ich denke, in diesem Fall bedeutet das, dass man nicht durch unangemessene Techniken (d. H. Klassenorientierte Programmierung) springen muss, bis man weiß, dass man ein Leistungsproblem hat. Auch dann debuggen Sie das Problem und suchen Sie nach dem am besten geeigneten.

2

Statische Methoden sind viel schneller und benötigen viel weniger Speicher. Es gibt dieses Missverständnis, dass es nur ein bisschen schneller ist. Es ist ein wenig schneller, solange Sie es nicht auf Schleifen legen. Übrigens, einige Schleifen sehen klein aus, sind aber nicht wirklich, weil der Methodenaufruf, der die Schleife enthält, auch eine andere Schleife ist. Sie können den Unterschied im Code erkennen, der die Renderfunktionen ausführt. In vielen Fällen stimmt leider viel weniger Speicher. Eine Instanz ermöglicht das einfache Teilen von Informationen mit Schwestermethoden. Eine statische Methode wird nach der Information fragen, wenn sie sie benötigt.

Aber wie im Fahren von Autos bringt Geschwindigkeit Verantwortung. Statische Methoden haben normalerweise mehr Parameter als ihr Instanzgegenstück. Da eine Instanz dafür sorgt, dass geteilte Variablen zwischengespeichert werden, sehen Ihre Instanzmethoden hübscher aus.

ShapeUtils.DrawCircle(stroke, pen, origin, radius); 

ShapeUtils.DrawSquare(stroke, pen, x, y, width, length); 

VS

ShapeUtils utils = new ShapeUtils(stroke,pen); 

util.DrawCircle(origin,radius); 

util.DrawSquare(x,y,width,length); 

In diesem Fall, wenn die Instanzvariablen von allen Methoden die meiste Zeit verwendet werden, sind beispielsweise Methoden ziemlich wert. Instanzen sind NICHT ÜBER STATE, es geht um SHARING, obwohl COMMON STATE eine natürliche Form des SHARING ist, sie sind NICHT DIE GLEICHEN. Als allgemeine Faustregel gilt: Wenn die Methode eng mit anderen Methoden gekoppelt ist - sie lieben einander so sehr, dass sie, wenn man sie anruft, auch die andere genannt werden muss und sie wahrscheinlich die gleiche Tasse Wasser teilen-- -, sollte es Instanz gemacht werden. Statische Methoden in Instanzmethoden zu übersetzen ist nicht so schwer. Sie müssen nur die gemeinsam genutzten Parameter verwenden und sie als Instanzvariablen angeben. Anders herum ist es schwieriger.

Oder Sie können eine Proxy-Klasse, die die statischen Methoden zu überbrücken. Während es in der Theorie vielleicht ineffizienter zu sein scheint, erzählt die Praxis eine andere Geschichte. Dies liegt daran, dass Sie immer dann, wenn Sie einmal (oder in einer Schleife) ein DrawSquare aufrufen müssen, direkt zur statischen Methode wechseln. Aber wann immer du es mit DrawCircle wieder und wieder verwenden willst, wirst du den Instanz-Proxy benutzen. Ein Beispiel sind die System.IO-Klassen FileInfo (Instanz) vs Datei (statisch).

Statische Methoden sind testbar. In der Tat sogar noch mehr als einmal testbar. Die Methode GetSum (x, y) wäre sehr gut testbar, nicht nur für den Komponententest, sondern auch für den Belastungstest, den integrierten Test und den Nutzungstest. Instanzmethoden sind gut für Komponententests, aber schrecklich für alle anderen Tests (was mehr zählt als Unitests BTW), weshalb wir heutzutage so viele Bugs bekommen. Die Sache, die ALLE Methoden untestable macht, sind Parameter, die keinen Sinn ergeben wie (Sender s, EventArgs e) oder globaler Zustand wie DateTime.Now. In der Tat sind statische Methoden so gut in der Testbarkeit, dass Sie weniger Fehler im C-Code einer neuen Linux-Distribution sehen als Ihr durchschnittlicher OO-Programmierer (er ist voll von S ***, ich weiß).

Verwandte Themen