Die Objektorientierung hat mir bei der Implementierung vieler Algorithmen sehr geholfen. Objektorientierte Sprachen führen Sie jedoch manchmal zu einem "einfachen" Ansatz, und ich bezweifle, dass dieser Ansatz immer eine gute Sache ist.
OO ist sehr hilfreich bei der schnellen und einfachen Codierung von Algorithmen. Aber könnte diese OOP ein Nachteil für leistungsbasierte Software sein, dh wie schnell wird das Programm ausgeführt?
Das Speichern von Diagrammknoten in einer Datenstruktur scheint zum Beispiel in erster Linie "unkompliziert" zu sein. Wenn Knotenobjekte jedoch viele Attribute und Methoden enthalten, kann dies zu einem langsamen Algorithmus führen?
Mit anderen Worten, könnten viele Referenzen zwischen vielen verschiedenen Objekten oder die Verwendung vieler Methoden aus vielen Klassen zu einer "schweren" Implementierung führen?
quelle
Antworten:
Die Objektorientierung kann aufgrund der Kapselung bestimmte algorithmische Optimierungen verhindern. Zwei Algorithmen mögen besonders gut zusammenarbeiten, aber wenn sie sich hinter OO-Schnittstellen verstecken, geht die Möglichkeit verloren, ihre Synergien zu nutzen.
Schauen Sie sich numerische Bibliotheken an. Viele von ihnen (nicht nur die, die in den 60ern oder 70ern geschrieben wurden) sind keine OOP. Es gibt einen Grund dafür: Numerische Algorithmen funktionieren besser als entkoppelte Gruppe
modules
als als OO-Hierarchien mit Schnittstellen und Kapselung.quelle
Was bestimmt die Leistung?
Die Grundlagen: Datenstrukturen, Algorithmen, Computerarchitektur, Hardware. Plus Aufwand.
Ein OOP-Programm kann dazu entworfen werden genau mit der Auswahl der Datenstrukturen und Algorithmen übereinstimmt, die nach der CS-Theorie als optimal erachtet werden. Es hat die gleichen Leistungsmerkmale wie das optimale Programm, zuzüglich eines gewissen Overheads. Der Overhead kann in der Regel minimiert werden.
Allerdings ist das ein Programm anfänglich nur mit OOP-Bedenken entworfen wurde, ohne die Grundlagen zu berücksichtigen, kann jedoch anfänglich suboptimal sein. Die Suboptimalität kann manchmal durch Umgestaltung beseitigt werden. Manchmal ist dies nicht der Fall - eine vollständige Umschreibung ist erforderlich.
Vorsichtsmaßnahme: Ist die Leistung von Unternehmenssoftware von Bedeutung?
Ja, aber Time-to-Market (TTM) ist um Größenordnungen wichtiger. Unternehmenssoftware legt den Schwerpunkt auf die Anpassbarkeit des Codes an komplexe Geschäftsregeln. Leistungsmessungen sollten während des gesamten Entwicklungslebenszyklus durchgeführt werden. (Siehe Abschnitt: Was bedeutet optimale Leistung? ) Es sollten nur marktfähige Verbesserungen vorgenommen und in späteren Versionen schrittweise eingeführt werden.
Was bedeutet optimale Leistung?
Im Allgemeinen besteht das Problem mit der Software-Leistung darin, dass, um zu beweisen, dass "eine schnellere Version existiert", diese schnellere Version zuerst existieren muss (dh kein anderer Beweis als er selbst).
Manchmal wird diese schnellere Version zuerst in einer anderen Sprache oder einem anderen Paradigma gesehen. Dies sollte als Hinweis auf eine Verbesserung verstanden werden, nicht als Beurteilung der Minderwertigkeit einiger anderer Sprachen oder Paradigmen.
Warum machen wir OOP, wenn dies unsere Suche nach optimaler Leistung behindert?
OOP führt Overhead (in Bezug auf Speicherplatz und Ausführung) ein, um die "Bearbeitbarkeit" und damit den Geschäftswert des Codes zu verbessern. Dies reduziert die Kosten für Weiterentwicklung und Optimierung. Siehe @ MikeNakis .
Welche Teile von OOP können ein anfänglich suboptimales Design fördern?
Die Teile von OOP, die (i) Einfachheit / Intuitivität fördern, (ii) Umgang mit umgangssprachlichen Entwurfsmethoden anstelle von Grundlagen, (iii) mehrere maßgeschneiderte Implementierungen desselben Zwecks verhindern.
Die strikte Anwendung einiger OOP-Richtlinien (Kapselung, Nachrichtenübergabe, eine Sache gut machen) führt in der Tat zunächst zu langsamerem Code. Leistungsmessungen helfen bei der Diagnose dieser Probleme. Solange die Datenstruktur und der Algorithmus mit dem theoretisch vorhergesagten optimalen Design übereinstimmen, kann der Overhead normalerweise minimiert werden.
Was sind die allgemeinen Abhilfemaßnahmen für OOP-Gemeinkosten?
Wie bereits erwähnt, werden Datenstrukturen verwendet, die für das Design optimal sind.
Einige Sprachen unterstützen Code-Inlining, wodurch eine gewisse Laufzeitleistung wiederhergestellt werden kann.
Wie könnten wir OOP einführen, ohne Leistung zu opfern?
Lernen und wenden Sie sowohl das OOP als auch die Grundlagen an.
Es ist wahr, dass die strikte Einhaltung von OOP Sie möglicherweise daran hindert, eine schnellere Version zu schreiben. Manchmal kann eine schnellere Version nur von Grund auf neu geschrieben werden. Aus diesem Grund ist es hilfreich, mehrere Codeversionen unter Verwendung verschiedener Algorithmen und Paradigmen (OOP, generisch, funktional, mathematisch, Spaghetti) zu schreiben und anschließend mithilfe von Optimierungstools jede Version an die beobachtete maximale Leistung heranzuführen.
Gibt es Codetypen, die von OOP nicht profitieren?
(Erweitert aus der Diskussion zwischen [@quant_dev], [@ SK-logic] und [@MikeNakis])
*
quelle
Dabei geht es nicht wirklich um Objektorientierung, sondern um Container. Wenn Sie eine doppelt verknüpfte Liste zum Speichern von Pixeln in Ihrem Videoplayer verwendet haben, leidet diese.
Wenn Sie jedoch den richtigen Container verwenden, gibt es keinen Grund, warum ein std :: vector langsamer als ein Array ist, und da Sie alle gängigen Algorithmen bereits dafür geschrieben haben - von Experten - ist er wahrscheinlich schneller als Ihr selbst geschriebener Array-Code.
quelle
OOP ist offensichtlich eine gute Idee und kann wie jede gute Idee überstrapaziert werden. Nach meiner Erfahrung ist es viel zu viel genutzt. Schlechte Leistung und schlechte Wartbarkeit sind die Folge.
Es hat nichts mit dem Aufwand zu tun, virtuelle Funktionen aufzurufen, und nicht viel mit dem, was der Optimierer / Jitter tut.
Es hat alles mit Datenstrukturen zu tun, die zwar die beste Big-O-Leistung aufweisen, jedoch sehr schlechte konstante Faktoren aufweisen. Dies erfolgt unter der Annahme, dass ein Leistungsproblem in der App an einer anderen Stelle auftritt.
Dies äußert sich zum einen darin, wie oft pro Sekunde eine neue Operation ausgeführt wird, für die eine O (1) -Leistung angenommen wird, die jedoch Hunderte bis Tausende von Anweisungen ausführen kann (einschließlich des entsprechenden Löschvorgangs) oder GC-Zeit). Dies kann durch Speichern der verwendeten Objekte verringert werden, macht den Code jedoch weniger "sauber".
Eine andere Art, wie sich dies manifestiert, ist die Art und Weise, wie Benutzer dazu ermutigt werden, Eigenschaftsfunktionen, Benachrichtigungshandler, Aufrufe von Basisklassenfunktionen und alle Arten von unterirdischen Funktionsaufrufen zu schreiben, um die Konsistenz aufrechtzuerhalten. Für die Aufrechterhaltung der Konsistenz sind sie von begrenztem Erfolg, aber sie sind äußerst erfolgreich darin, Zyklen zu verschwenden. Programmierer verstehen das Konzept normalisierter Daten , wenden diese jedoch in der Regel nur auf das Datenbankdesign an. Sie wenden es nicht auf das Datenstrukturdesign an, zumindest nicht, weil OOP ihnen sagt, dass sie es nicht müssen. So einfach wie das Setzen eines Modified-Bits in einem Objekt kann es zu einem Tsunami von Aktualisierungen in der Datenstruktur kommen, da keine Klasse, die ihren Code wert ist, einen Modified-Aufruf annimmt und ihn nur speichert .
Vielleicht ist die Leistung einer bestimmten App genau so, wie sie geschrieben wurde.
Auf der anderen Seite, wenn es ein Leistungsproblem gibt, ist hier ein Beispiel, wie ich es tune. Es ist ein mehrstufiger Prozess. In jeder Phase entfällt ein großer Teil der Zeit auf bestimmte Aktivitäten, die durch etwas Schnelleres ersetzt werden könnten. (Ich habe nicht "Engpass" gesagt. Dies sind nicht die Dinge, die Profiler gut finden können.) Dieser Prozess erfordert häufig, um die Beschleunigung zu erreichen, einen umfassenden Austausch der Datenstruktur. Häufig ist diese Datenstruktur nur vorhanden, weil die OOP-Praxis empfohlen wird.
quelle
Theoretisch könnte dies zu Langsamkeit führen, aber selbst dann wäre es kein langsamer Algorithmus, sondern eine langsame Implementierung. In der Praxis können Sie anhand der Objektorientierung verschiedene Was-wäre-wenn-Szenarien ausprobieren (oder den Algorithmus in Zukunft überarbeiten) und so algorithmische Verbesserungen vornehmen, die Sie nicht erhoffen könnten, wenn Sie ihn in der ersten Phase auf Spaghetti-Weise geschrieben hätten Ort, denn die Aufgabe wäre entmutigend. (Sie müssten im Wesentlichen die ganze Sache umschreiben.)
Wenn Sie beispielsweise die verschiedenen Aufgaben und Entitäten in bereinigte Objekte unterteilt haben, können Sie möglicherweise später problemlos eine Caching-Funktion zwischen einige (für sie transparente) Objekte einbetten, die zu Tausenden von Ergebnissen führen kann. Falte Verbesserung.
Im Allgemeinen führen die Arten von Verbesserungen, die Sie mit einer einfachen Sprache erreichen können (oder clevere Tricks mit einer höheren Sprache), zu konstanten (linearen) Zeitverbesserungen, die in der Big-Oh-Notation nicht berücksichtigt werden. Mit algorithmischen Verbesserungen können Sie möglicherweise nichtlineare Verbesserungen erzielen. Das ist unbezahlbar.
quelle
Oft ja !!! ABER...
Nicht unbedingt. Dies hängt von der Sprache / dem Compiler ab. Zum Beispiel wird ein optimierender C ++ - Compiler, vorausgesetzt, Sie verwenden keine virtuellen Funktionen, Ihren Objekt-Overhead häufig auf Null reduzieren. Sie können beispielsweise einen Wrapper über
int
einen solchen schreiben oder einen intelligenten Zeiger mit Gültigkeitsbereich über einen einfachen alten Zeiger, der genauso schnell arbeitet wie die direkte Verwendung dieser einfachen alten Datentypen.In anderen Sprachen wie Java ist der Aufwand für ein Objekt geringfügig (in vielen Fällen recht gering, in einigen seltenen Fällen jedoch astronomisch, wenn es sich um sehr kleine Objekte handelt). Beispielsweise ist
Integer
es wesentlich weniger effizient alsint
(benötigt 16 Bytes im Gegensatz zu 4 bei 64-Bit). Dabei handelt es sich nicht nur um krassen Müll oder ähnliches. Im Gegenzug bietet Java die Möglichkeit, jeden benutzerdefinierten Typ einheitlich zu reflektieren und alle nicht als gekennzeichneten Funktionen außer Kraft zu setzenfinal
.Nehmen wir jedoch das beste Szenario: den optimierenden C ++ - Compiler, mit dem Objektschnittstellen bis auf Null optimiert werden können . Selbst dann verschlechtert OOP häufig die Leistung und verhindert, dass sie den Höchstwert erreicht. Das mag sich wie ein komplettes Paradox anhören: Wie könnte es sein? Das Problem liegt in:
Interface Design und Encapsulation
Das Problem ist, dass selbst wenn ein Compiler die Struktur eines Objekts auf Null reduzieren kann (was zumindest sehr oft für die Optimierung von C ++ - Compilern zutrifft), die Kapselung und das Schnittstellendesign (und die angesammelten Abhängigkeiten) von feinkörnigen Objekten häufig das verhindern Optimalste Datendarstellung für Objekte, die von der Masse aggregiert werden sollen (was bei leistungskritischer Software häufig der Fall ist).
Nehmen Sie dieses Beispiel:
Angenommen, unser Speicherzugriffsmuster besteht darin, diese Partikel einfach nacheinander zu durchlaufen und sie wiederholt um jedes Bild zu bewegen, sie von den Ecken des Bildschirms abzuprallen und dann das Ergebnis zu rendern.
Es ist bereits ein eklatanter 4-Byte-Padding-Overhead zu sehen, der erforderlich ist, um das
birth
Element ordnungsgemäß auszurichten , wenn Partikel zusammenhängend aggregiert werden. Bereits ~ 16,7% des Speichers werden mit dem für die Ausrichtung verwendeten Totraum verschwendet.Dies könnte problematisch erscheinen, da wir heutzutage Gigabyte DRAM haben. Doch selbst die scheußlichsten Maschinen, die wir heute haben, haben oft nur 8 Megabyte, wenn es um die langsamste und größte Region des CPU-Caches (L3) geht. Je weniger wir hineinpassen können, desto mehr zahlen wir für den wiederholten DRAM-Zugriff und desto langsamer wird es. Plötzlich scheint es nicht mehr trivial zu sein, 16,7% des Arbeitsspeichers zu verschwenden.
Diesen Overhead können wir leicht beseitigen, ohne die Ausrichtung des Feldes zu beeinträchtigen:
Jetzt haben wir den Speicher von 24 MB auf 20 MB reduziert. Mit einem sequentiellen Zugriffsmuster verbraucht das Gerät diese Daten jetzt viel schneller.
Aber schauen wir uns dieses
birth
Feld etwas genauer an. Nehmen wir an, es zeichnet die Startzeit auf, zu der ein Partikel geboren (erzeugt) wird. Stellen Sie sich vor, auf das Feld wird nur zugegriffen, wenn ein Partikel zum ersten Mal erstellt wird, und alle 10 Sekunden, um zu prüfen, ob ein Partikel stirbt und an einer zufälligen Stelle auf dem Bildschirm wiedergeboren wird. In diesem Fallbirth
ist ein kaltes Feld. In unseren leistungskritischen Schleifen wird nicht darauf zugegriffen.Infolgedessen sind die tatsächlichen leistungskritischen Daten nicht 20 Megabyte, sondern ein zusammenhängender Block von 12 Megabyte. Der aktuelle Arbeitsspeicher, auf den wir häufig zugreifen, ist auf die Hälfte seiner Größe geschrumpft ! Erwarten Sie erhebliche Geschwindigkeitssteigerungen gegenüber unserer ursprünglichen 24-Megabyte-Lösung (muss nicht gemessen werden - wurde bereits tausend Mal durchgeführt, ist aber im Zweifelsfall unverbindlich).
Beachten Sie jedoch, was wir hier gemacht haben. Wir haben die Einkapselung dieses Partikelobjekts vollständig aufgehoben. Sein Status ist jetzt zwischen
Particle
den privaten Feldern eines Typs und einem separaten, parallelen Array aufgeteilt. Und hier steht granulares objektorientiertes Design im Weg.Wir können die optimale Datendarstellung nicht ausdrücken, wenn wir uns auf das Interface-Design eines einzelnen, sehr granularen Objekts wie eines einzelnen Partikels, eines einzelnen Pixels, sogar eines einzelnen 4-Komponenten-Vektors, möglicherweise sogar eines einzelnen "Kreaturen" -Objekts in einem Spiel beschränken usw. Die Geschwindigkeit eines Geparden wird verschwendet, wenn er auf einer 2 Quadratmeter großen kleinen Insel steht, und genau das leistet ein sehr granulares objektorientiertes Design häufig in Bezug auf die Leistung. Es beschränkt die Datendarstellung auf einen suboptimalen Charakter.
Nehmen wir an, wir bewegen nur Partikel, und greifen in drei separaten Schleifen auf deren x / y / z-Felder zu. In diesem Fall können wir von der SoA-ähnlichen SIMD-Struktur mit AVX-Registern profitieren, die 8 SPFP-Operationen parallel vektorisieren können. Aber um dies zu tun, müssen wir jetzt diese Darstellung verwenden:
Jetzt fliegen wir mit der Partikelsimulation, aber schauen Sie, was mit unserem Partikeldesign passiert ist. Es wurde komplett abgerissen und wir betrachten nun 4 parallele Arrays und haben kein Objekt, sie zu aggregieren. Unser objektorientiertes
Particle
Design ist sayonara gegangen.Das ist mir schon oft passiert, als ich in leistungskritischen Bereichen gearbeitet habe, in denen Benutzer Geschwindigkeit fordern und nur die Korrektheit das ist, was sie mehr fordern. Diese kleinen, winzigen objektorientierten Entwürfe mussten abgerissen werden, und die Kaskadenbrüche erforderten oft eine langsame Abschreibungsstrategie für den schnelleren Entwurf.
Lösung
Das obige Szenario stellt nur ein Problem bei granularen objektorientierten Designs dar. In diesen Fällen müssen wir häufig die Struktur abreißen, um effizientere Darstellungen als Ergebnis von SoA-Wiederholungen, Aufteilen von Heiß- / Kaltfeldern und Reduzierung des Paddings für sequentielle Zugriffsmuster zu erzielen (Padding ist manchmal hilfreich für die Leistung bei wahlfreiem Zugriff) Muster in AoS-Fällen, aber fast immer ein Hindernis für sequentielle Zugriffsmuster usw.
Wir können jedoch diese endgültige Darstellung übernehmen und dennoch eine objektorientierte Schnittstelle modellieren:
Jetzt geht es uns gut. Wir können alle objektorientierten Goodies bekommen, die wir mögen. Der Gepard hat ein ganzes Land, durch das er so schnell wie möglich rennen kann. Unsere Schnittstellendesigns führen uns nicht länger in eine Engpass-Ecke.
ParticleSystem
kann möglicherweise sogar abstrakt sein und virtuelle Funktionen verwenden. Es ist strittig, wir zahlen für den Overhead auf Partikelebene anstatt auf Partikelebene . Der Overhead beträgt 1 / 1.000.000stel dessen, was sonst wäre, wenn wir Objekte auf der Ebene der einzelnen Partikel modellieren würden.Das ist also die Lösung in wirklich leistungskritischen Bereichen, die eine hohe Last bewältigen, und für alle Arten von Programmiersprachen (von dieser Technik profitieren C, C ++, Python, Java, JavaScript, Lua, Swift usw.). Und es kann nicht einfach als "vorzeitige Optimierung" bezeichnet werden, da es sich um das Interface-Design und die Architektur der . Wir können keine Codebasis schreiben, die ein einzelnes Partikel als Objekt mit einer Schiffsladung von Client-Abhängigkeiten zu a modelliert
Particle's
öffentliche Schnittstelle und dann später unsere Meinung ändern. Das habe ich oft getan, als ich aufgerufen wurde, um ältere Codebasen zu optimieren, und es kann Monate dauern, Zehntausende von Codezeilen sorgfältig umzuschreiben, um das umfangreichere Design zu verwenden. Dies wirkt sich idealerweise darauf aus, wie wir die Dinge im Voraus gestalten, vorausgesetzt, wir können mit einer hohen Last rechnen.Ich halte diese Antwort in der einen oder anderen Form in vielen Performance-Fragen, insbesondere im Zusammenhang mit objektorientiertem Design, aufrecht. Objektorientiertes Design kann immer noch mit den höchsten Leistungsanforderungen kompatibel sein, aber wir müssen die Art und Weise, wie wir darüber nachdenken, ein wenig ändern. Wir müssen dem Geparden etwas Raum geben, damit er so schnell wie möglich rennt, und das ist oft unmöglich, wenn wir kleine Objekte entwerfen, die kaum irgendeinen Zustand speichern.
quelle
Ja, die objektorientierte Denkweise kann auf jeden Fall neutral oder negativ sein, wenn es um Hochleistungsprogrammierung geht, sowohl auf algorithmischer als auch auf Implementierungsebene. Wenn OOP die algorithmische Analyse ersetzt, kann dies zu einer vorzeitigen Implementierung führen, und auf der untersten Ebene müssen die OOP-Abstraktionen beiseite gelegt werden.
Das Problem ergibt sich aus der Betonung von OOP auf das Nachdenken über einzelne Instanzen. Ich denke, es ist fair zu sagen, dass die OOP-Denkweise über einen Algorithmus darin besteht, über einen bestimmten Satz von Werten nachzudenken und ihn auf diese Weise zu implementieren. Wenn dies Ihr Weg auf höchster Ebene ist, ist es unwahrscheinlich, dass Sie eine Transformation oder Restrukturierung realisieren, die zu Big O-Gewinnen führen würde.
Auf der algorithmischen Ebene wird oft an das Gesamtbild und die Einschränkungen oder Beziehungen zwischen Werten gedacht, die zu Big-O-Gewinnen führen. Ein Beispiel könnte sein, dass es in der OOP-Denkweise nichts gibt, was Sie dazu bringen würde, "einen kontinuierlichen Bereich von Ganzzahlen zu summieren" von einer Schleife zu transformieren
(max + min) * n/2
Auf der Implementierungsebene sind Computer zwar für die meisten Algorithmen auf Anwendungsebene "schnell genug", bei leistungskritischem Code auf niedriger Ebene ist jedoch die Lokalität von großer Bedeutung. Die OOP-Betonung auf das Nachdenken über eine einzelne Instanz und die Werte eines Durchgangs durch die Schleife kann wiederum negativ sein. In leistungsfähigem Code möchten Sie die Schleife möglicherweise nicht einfach schreiben, sondern nur teilweise abrollen, mehrere Ladeanweisungen oben gruppieren, sie dann in eine Gruppe umwandeln und dann in eine Gruppe schreiben. Währenddessen würden Sie auf Zwischenberechnungen und vor allem auf den Cache- und Speicherzugriff achten. Probleme, bei denen die OOP-Abstraktionen nicht mehr gültig sind. Und wenn man es befolgt, kann es irreführend sein: Auf dieser Ebene muss man die Repräsentationen auf Maschinenebene kennen und darüber nachdenken.
Wenn Sie sich etwas wie die Performance Primitives von Intel ansehen, haben Sie buchstäblich Tausende von Implementierungen der Fast Fourier Transform, von denen jede optimiert wurde, um für eine bestimmte Datengröße und Maschinenarchitektur besser zu funktionieren. (Faszinierenderweise stellt sich heraus, dass der Großteil dieser Implementierungen maschinengeneriert ist: Markus Püschel Automatic Performance Programming )
Wie in den meisten Antworten bereits erwähnt, ist OOP für die meiste Entwicklung und für die meisten Algorithmen für die Leistung irrelevant. Solange Sie nicht "vorzeitig pessimisieren" und viele nicht-lokale Anrufe hinzufügen, ist der
this
Zeiger weder hier noch da.quelle
Es ist verwandt und oft übersehen.
Es ist keine einfache Antwort, es hängt davon ab, was Sie tun möchten.
Einige Algorithmen weisen eine bessere Leistung bei Verwendung einer einfach strukturierten Programmierung auf, während andere eine bessere Objektorientierung verwenden.
Vor der Objektorientierung unterrichten viele Schulen das Design von Algorithmen mit strukturierter Programmierung. Heutzutage unterrichten viele Schulen objektorientiertes Programmieren und ignorieren dabei Algorithmus-Design und -Leistung.
Natürlich gab es dort Schulen, die strukturiertes Programmieren lehrten, die sich überhaupt nicht für Algorithmen interessierten.
quelle
Die Leistung hängt letztendlich von den CPU- und Speicherzyklen ab. Der prozentuale Unterschied zwischen dem Overhead von OOP-Messaging und -Kapselung und einer offeneren Programmiersemantik kann jedoch signifikant genug sein oder auch nicht, um einen spürbaren Unterschied in der Leistung Ihrer Anwendung zu bewirken. Wenn eine App an eine Festplatte oder einen Daten-Cache gebunden ist, kann jeglicher OOP-Overhead durch das Rauschen vollständig verloren gehen.
In den inneren Schleifen der Echtzeit-Signal- und Bildverarbeitung und in anderen numerisch rechengebundenen Anwendungen kann der Unterschied jedoch ein erheblicher Prozentsatz der CPU- und Speicherzyklen sein, was die Ausführung von OOP-Overhead erheblich verteuern kann.
Die Semantik einer bestimmten OOP-Sprache kann genügend Möglichkeiten für den Compiler bieten oder nicht, um diese Zyklen zu optimieren, oder damit die Verzweigungsvorhersageschaltungen der CPU immer richtig raten und diese Zyklen mit Pre-Fetch und Pipelining abdecken.
quelle
Ein gutes objektorientiertes Design hat mir geholfen, eine Anwendung erheblich zu beschleunigen. A musste auf algorithmische Weise komplexe Grafiken erzeugen. Ich habe es durch Microsoft Visio-Automatisierung gemacht. Ich habe gearbeitet, war aber unglaublich langsam. Glücklicherweise hatte ich eine zusätzliche Abstraktionsebene zwischen der Logik (dem Algorithmus) und dem Visio-Material eingefügt. Meine Visio-Komponente hat ihre Funktionalität über eine Schnittstelle verfügbar gemacht. Dadurch konnte ich die langsame Komponente leicht durch eine andere SVG-Datei ersetzen, die mindestens 50-mal schneller war! Ohne eine saubere objektorientierte Herangehensweise wären die Codes für den Algorithmus und die Vision-Steuerung auf eine Weise verwickelt gewesen, die die Änderung in einen Albtraum verwandelt hätte.
quelle