Wenn Sie eine CPU- oder GPU-intensive Anwendung auf dem iPhone oder einer anderen tragbaren Hardware programmieren, müssen Sie kluge algorithmische Entscheidungen treffen, um Ihren Code schnell zu machen.
Aber selbst gute Algorithmusoptionen können langsam sein, wenn die von Ihnen verwendete Sprache schlechter abschneidet als eine andere.
Gibt es harte Daten, die Objective-C mit C ++ vergleichen, insbesondere auf dem iPhone, aber möglicherweise nur auf dem Mac-Desktop, um verschiedene ähnliche Sprachaspekte zu erfüllen? Ich bin mit diesem Artikel zum Vergleich von C und Objective-C sehr vertraut , aber dies ist eine größere Frage des Vergleichs zweier objektorientierter Sprachen miteinander.
Ist eine C ++ vtable-Suche beispielsweise wirklich schneller als eine Obj-C-Nachricht? Wie viel schneller? Threading, Polymorphismus, Sortieren usw. Bevor ich mich auf die Suche nach einem Projekt mit doppelten Objektmodellen und verschiedenen Testcodes mache, möchte ich wissen, ob dies bereits jemand getan hat und was die Ergebnisse wo sind. Diese Art des Testens und Vergleichens ist ein Projekt für sich und kann viel Zeit in Anspruch nehmen. Vielleicht ist dies nicht ein Projekt, sondern zwei und nur die Ergebnisse können verglichen werden.
I'm looking for hard data, not evangelism. Like many of you I love and hate both languages for various reasons. Furthermore, if there is someone out there actively pursuing this same thing I'd be interesting in pitching in some code to see the end results, and I'm sure others would help out too. My guess is that they both have strengths and weaknesses, my goal is to find out precisely what they are so that they can be avoided/exploited in real-world scenarios.
Antworten:
Mike Ash hat in seinem Beitrag "Leistungsvergleiche allgemeiner Operationen" einige harte Zahlen für die Leistung verschiedener Objective-C-Methodenaufrufe im Vergleich zu C und C ++ . Auch dieser Beitrag von Savoy Software ist eine interessante Lektüre , wenn es darum geht , die Leistung einer iPhone - Anwendung Abstimmung von Objective-C ++.
Ich bevorzuge die saubere, beschreibende Syntax von Objective-C gegenüber Objective-C ++ und habe nicht festgestellt, dass die Sprache selbst die Ursache für meine Leistungsengpässe ist. Ich neige sogar dazu, Dinge zu tun, von denen ich weiß, dass sie ein wenig Leistung opfern, wenn sie meinen Code viel wartbarer machen.
quelle
Ja, gut geschriebenes C ++ ist erheblich schneller. Wenn Sie leistungskritische Programme schreiben und Ihr C ++ nicht so schnell wie C ist (oder innerhalb weniger Prozent), stimmt etwas nicht. Wenn Ihre ObjC-Implementierung so schnell wie C ist, stimmt normalerweise etwas nicht - dh das Programm ist wahrscheinlich ein schlechtes Beispiel für ObjC OOD, da es wahrscheinlich einige "schmutzige" Tricks verwendet, um unter die Abstraktionsschicht zu treten, in der es arbeitet, z. B. direkt ivar zugreift.
Der 'Vergleich' von Mike Ash ist sehr irreführend - ich würde niemals empfehlen, die Ausführungszeiten von Programmen zu vergleichen, die Sie geschrieben haben, oder C vs C ++ vs ObjC zu vergleichen. Die dargestellten Ergebnisse stammen aus einem Test mit deaktivierten Compiler-Optimierungen . Ein Programm, das mit deaktivierten Optimierungen kompiliert wurde, ist selten relevant, wenn Sie Ausführungszeiten messen. Es ist fehlerhaft, es als Benchmark anzusehen, der C ++ mit Objective-C vergleicht. Der Test vergleicht auch einzelne Funktionen und nicht ganze, für die reale Welt optimierte Implementierungen. Einzelne Funktionen werden mit beiden Sprachen auf sehr unterschiedliche Weise kombiniert. Dies ist alles andere als ein realistischer Leistungsmaßstab für optimierte Implementierungen. Beispiele: Mit aktivierten Optimierungen ,
IMP
Der Cache ist so langsam wie virtuelle Funktionsaufrufe. Der statische Versand (im Gegensatz zum dynamischen Versand, z. B. unter Verwendungvirtual
) und Aufrufe bekannter C ++ - Typen (bei denen der dynamische Versand möglicherweise umgangen wird) können aggressiv optimiert werden. Dieser Prozess wird als Devirtualisierung bezeichnet, und wenn er verwendet wird, kann eine deklarierte Elementfunktionvirtual
sogarinline
d sein. Im Fall des Mike Ash-Tests, bei dem viele Aufrufe an deklarierte Mitgliedsfunktionenvirtual
mit leeren Körpern erfolgen: Diese Aufrufe werden in optimierten Builds vollständig wenn der Typ bekannt ist, da der Compiler die Implementierung sieht und den dynamischen Versand bestimmen kann nicht notwendig. Der Compiler kann auch Aufrufe von eliminierenmalloc
optimiert (zugunsten der Stapelspeicherung). Das Aktivieren von Compiler-Optimierungen in C, C ++ oder Objective-C kann daher zu dramatischen Unterschieden bei den Ausführungszeiten führen.Das heißt nicht, dass die präsentierten Ergebnisse völlig nutzlos sind. Sie können nützliche Informationen zu externen APIs erhalten, wenn Sie feststellen möchten, ob es messbare Unterschiede zwischen der Zeit gibt, die sie auf
pthread_create
oder+[NSObject alloc]
auf einer Plattform oder Architektur verbringen, und einer anderen. In diesen beiden Beispielen werden natürlich optimierte Implementierungen in Ihrem Test verwendet (es sei denn, Sie entwickeln sie gerade). Aber um eine Sprache in Programmen, die Sie kompilieren, mit einer anderen zu vergleichen, sind die dargestellten Ergebnisse bei deaktivierten Optimierungen nutzlos.Objekterstellung
Berücksichtigen Sie auch die Objekterstellung in ObjC - jedes Objekt wird dynamisch zugewiesen (z. B. auf dem Heap). Mit C ++ können Objekte auf dem Stapel (z. B. ungefähr so schnell wie das Erstellen einer C-Struktur und das Aufrufen einer einfachen Funktion in vielen Fällen), auf dem Heap oder als Elemente abstrakter Datentypen erstellt werden. Jedes Mal, wenn Sie zuweisen und freigeben (z. B. über malloc / free), können Sie eine Sperre einführen. Wenn Sie eine C-Struktur oder ein C ++ - Objekt auf dem Stapel erstellen, ist keine Sperre erforderlich (obwohl interne Mitglieder möglicherweise Heap-Zuweisungen verwenden), und dies kostet häufig nur einige Anweisungen oder einige Anweisungen plus einen Funktionsaufruf.
ObjC-Objekte sind ebenfalls Instanzen mit Referenzzählung. Die tatsächliche Notwendigkeit, dass ein Objekt ein
std::shared_ptr
leistungskritisches C ++ ist, ist sehr selten. In C ++ ist es nicht erforderlich oder wünschenswert, jede Instanz zu einer gemeinsam genutzten Instanz mit Referenzzählung zu machen. Mit C ++ haben Sie viel mehr Kontrolle über Besitz und Lebensdauer.Arrays und Sammlungen
Arrays und viele Sammlungen in C und C ++ verwenden ebenfalls stark typisierte Container und zusammenhängenden Speicher. Da die Adresse der Mitglieder des nächsten Elements häufig bekannt ist, kann der Optimierer viel mehr und Sie haben eine hervorragende Cache- und Speicherlokalität. Mit ObjC ist dies für Standardobjekte (z
NSObject
. B. ) weit von der Realität entfernt .Versand
In Bezug auf Methoden verwenden viele C ++ - Implementierungen nur wenige virtuelle / dynamische Aufrufe, insbesondere in hochoptimierten Programmen. Dies sind statische Methodenaufrufe und Futter für die Optimierer.
Bei ObjC-Methoden ist jeder Methodenaufruf (objc message send) dynamisch und folglich eine Firewall für den Optimierer. Letztendlich führt dies zu vielen Einschränkungen oder Unannehmlichkeiten in Bezug darauf, was Sie tun können und was nicht, um die Leistung beim Schreiben von leistungskritischem ObjC auf ein Minimum zu beschränken. Dies kann zu größeren Methoden, IMP-Caching und häufiger Verwendung von C führen.
Einige Echtzeitanwendungen können keine ObjC-Nachrichten in ihren Renderpfaden verwenden. Keine - Audio-Rendering ist ein gutes Beispiel dafür. Der ObjC-Versand ist einfach nicht für Echtzeitzwecke konzipiert. Zuweisungen und Sperren können hinter den Kulissen beim Versenden von Nachrichtenobjekten auftreten, wodurch die Komplexität / Zeit des Objektnachrichtens unvorhersehbar genug wird, dass das Audio-Rendering möglicherweise seine Frist verpasst.
Andere Eigenschaften
C ++ bietet auch Generika- / Vorlagenimplementierungen für viele seiner Bibliotheken. Diese optimieren sehr gut. Sie sind typsicher, und viele Inlining- und Optimierungsvorgänge können mit Vorlagen durchgeführt werden (Polymorphismus, Optimierung und Spezialisierung, die bei der Kompilierung stattfinden). C ++ fügt mehrere Funktionen hinzu, die in striktem ObjC einfach nicht verfügbar oder vergleichbar sind. Der Versuch, langs, Objekte und Bibliotheken, die sehr unterschiedlich sind, direkt zu vergleichen, ist nicht so nützlich - es ist eine sehr kleine Teilmenge der tatsächlichen Realisierungen. Es ist besser, die Frage auf eine Bibliothek / ein Framework oder ein reales Programm zu erweitern, wobei viele Aspekte des Designs und der Implementierung berücksichtigt werden.
Andere Punkte
C- und C ++ - Symbole können in verschiedenen Phasen des Builds (Strippen, Eliminieren von totem Code, Inlining und frühes Inlining sowie Optimierung der Verbindungszeit) einfacher entfernt und optimiert werden. Zu den Vorteilen gehören reduzierte Binärgrößen, reduzierte Start- / Ladezeiten, reduzierter Speicherverbrauch usw. Für eine einzelne App ist dies möglicherweise keine so große Sache. Wenn Sie jedoch viel Code wiederverwenden und dies auch tun sollten, könnten Ihre gemeinsam genutzten Bibliotheken dem Programm bei Verwendung von ObjC viel unnötiges Gewicht hinzufügen - es sei denn, Sie sind bereit, durch einige brennende Reifen zu springen. Skalierbarkeit und Wiederverwendung sind daher auch Faktoren bei mittleren / großen Projekten und Gruppen, bei denen die Wiederverwendung hoch ist.
Enthaltene Bibliotheken
ObjC-Bibliotheksimplementierer optimieren auch für die Umgebung, sodass die Bibliotheksimplementierer einige Sprach- und Umgebungsfunktionen verwenden können, um optimierte Implementierungen anzubieten. Obwohl es beim Schreiben eines optimierten Programms in reinem ObjC einige ziemlich erhebliche Einschränkungen gibt, gibt es in Cocoa einige hochoptimierte Implementierungen. Dies ist eine der Stärken von Cocoa, obwohl die C ++ - Standardbibliothek (wie manche Leute die STL nennen) auch keine Lücke ist. Cocoa arbeitet auf einer viel höheren Abstraktionsebene als C ++ - wenn Sie nicht genau wissen, was Sie tun (oder tun sollten), kann es Sie wirklich kosten , näher am Metall zu arbeiten. Es ist eine gute Sache, auf eine gute Bibliotheksimplementierung zurückzugreifen, wenn Sie kein Experte auf einem bestimmten Gebiet sind, es sei denn, Sie sind wirklich bereit zu lernen. Auch die Umgebungen von Cocoa sind begrenzt. Sie können Implementierungen / Optimierungen finden, die das Betriebssystem besser nutzen.
Wenn Sie optimierte Programme schreiben und Erfahrung in C ++ und ObjC haben, sind saubere C ++ - Implementierungen oft doppelt so schnell oder schneller als sauberes ObjC (ja, Sie können es mit Cocoa vergleichen). Wenn Sie wissen, wie man optimiert, können Sie häufig bessere Abstraktionen als allgemeine Abstraktionen auf höherer Ebene durchführen. Einige optimierte C ++ - Implementierungen sind jedoch genauso schnell oder langsamer als die von Cocoa (z. B. war mein erster Versuch, Datei-E / A zu erstellen, langsamer als der von Cocoa - hauptsächlich, weil die C ++ - Implementierung den Speicher initialisiert).
Vieles hängt von den Sprachfunktionen ab, mit denen Sie vertraut sind. Ich benutze beide langs, beide haben unterschiedliche Stärken und Modelle / Muster. Sie ergänzen sich recht gut und es gibt großartige Bibliotheken für beide. Wenn Sie ein komplexes, leistungskritisches Programm implementieren, bietet die korrekte Verwendung der Funktionen und Bibliotheken von C ++ viel mehr Kontrolle und bietet erhebliche Vorteile für die Optimierung, sodass in den richtigen Händen "um ein Vielfaches schneller" eine gute Standarderwartung ist ( Erwarten Sie jedoch nicht, jedes Mal oder ohne Arbeit zu gewinnen. Denken Sie daran, es dauert Jahre, um C ++ gut genug zu verstehen, um diesen Punkt wirklich zu erreichen.
Ich behalte den Großteil meiner leistungskritischen Pfade als C ++ bei, erkenne aber auch, dass ObjC auch eine sehr gute Lösung für einige Probleme ist und dass einige sehr gute Bibliotheken verfügbar sind.
quelle
Es ist sehr schwer, "harte Daten" dafür zu sammeln, die nicht irreführend sind.
Das größte Problem bei einem von Ihnen vorgeschlagenen Feature-to-Feature-Vergleich besteht darin, dass die beiden Sprachen sehr unterschiedliche Codierungsstile fördern. Objective-C ist eine dynamische Sprache mit Ententypisierung, bei der die typische C ++ - Verwendung statisch ist. Das gleiche objektorientierte Architekturproblem hätte wahrscheinlich sehr unterschiedliche ideale Lösungen unter Verwendung von C ++ oder Objective-C.
Mein Gefühl (da ich viel in beiden Sprachen programmiert habe, hauptsächlich in großen Projekten): Um die Objective-C-Leistung zu maximieren, muss es sehr nahe an C geschrieben werden. Während es mit C ++ möglich ist, die Sprache ohne viel mehr zu nutzen jede Leistungsstrafe im Vergleich zu C.
Welches ist besser? Ich weiß es nicht. Für reine Leistung hat C ++ immer die Nase vorn. Aber der OOP-Stil von Objective-C hat definitiv seine Vorzüge. Ich denke definitiv, dass es einfacher ist, eine vernünftige Architektur beizubehalten.
quelle
Dies kann wirklich nicht allgemein beantwortet werden, da es wirklich davon abhängt, wie Sie die Sprachfunktionen verwenden. Beide Sprachen haben Dinge, in denen sie schnell sind, Dinge, in denen sie langsam sind, und Dinge, die manchmal schnell und manchmal langsam sind. Es hängt wirklich davon ab, was Sie verwenden und wie Sie es verwenden. Der einzige Weg, um sicher zu sein, besteht darin, Ihren Code zu profilieren.
In Objective C können Sie auch C ++ - Code schreiben, sodass es möglicherweise einfacher ist, in Objective C zu codieren. Wenn Sie etwas finden, das darin nicht gut funktioniert, können Sie versuchen, eine C ++ - Version zu schreiben davon und zu sehen, ob das hilft (C ++ neigt dazu, zur Kompilierungszeit besser zu optimieren). Ziel C ist einfacher zu verwenden, wenn auch APIs geschrieben sind, mit denen Sie eine Schnittstelle herstellen. Außerdem ist der OOP-Stil möglicherweise einfacher oder flexibler.
Am Ende sollten Sie mit dem arbeiten, von dem Sie wissen, dass Sie sicheren, robusten Code schreiben können. Wenn Sie einen Bereich finden, der von der anderen Sprache besondere Aufmerksamkeit erfordert, können Sie zu diesem Bereich wechseln. Mit X-Code können Sie beide im selben Projekt kompilieren.
quelle
Ich habe ein paar Tests, die ich vor fast 2 Jahren auf einem iPhone 3G durchgeführt habe. Damals gab es keine Dokumentation oder harte Zahlen. Ich bin mir nicht sicher, wie gültig sie noch sind, aber der Quellcode wird veröffentlicht und angehängt.
Dies ist kein sehr umfangreicher Test. Ich war hauptsächlich an NSArray vs C Array interessiert, um eine große Anzahl von Objekten zu iterieren.
http://memo.tv/nsarray_vs_c_array_performance_comparison
http://memo.tv/nsarray_vs_c_array_performance_comparison_part_ii_makeobjectsperformselector
Sie können sehen, dass das C-Array bei hohen Iterationen viel schneller ist. Seitdem habe ich festgestellt, dass der Engpass wahrscheinlich nicht die Iteration des NSArray ist, sondern das Senden der Nachricht. Ich wollte methodForSelector ausprobieren und die Methoden direkt aufrufen, um zu sehen, wie groß der Unterschied sein würde, kam aber nie dazu. Laut den Benchmarks von Mike Ash ist es etwas mehr als fünfmal schneller.
quelle
NSArray
Ich habe keine harten Daten für Objective C, aber ich habe einen guten Ort, um nach C ++ zu suchen.
C ++ begann als C mit Klassen nach Bjarne Stroustroup in seiner Reflexion über die frühen Jahre von C ++ ( http://www2.research.att.com/~bs/hopl2.pdf) ), so dass C ++ (wie Ziel C) gedacht werden kann ) als C an seine Grenzen für die Objektorientierung zu bringen.
Was sind diese Grenzen? Im Zeitraum 1994-1997 stellten viele Forscher fest, dass die Objektorientierung aufgrund der dynamischen Bindung mit Kosten verbunden ist, z. B. wenn C ++ - Funktionen als virtuell markiert sind und möglicherweise untergeordnete Klassen vorhanden sind, die diese Funktionen überschreiben. (In Java und C # erwarten alle Funktionen, dass Ctors von Natur aus virtuell sind, und Sie können nicht viel dagegen tun.) In "Eine Studie über Devirtualisierungstechniken für einen Java-Just-In-Time-Compiler" von Forschern von IBM Research Tokyo, Sie kontrastieren die Techniken, die verwendet werden, um damit umzugehen, darunter eine von Urz Hölzle und Gerald Aigner. Urz Hölzle hatte in einem separaten Artikel mit Karel Driesen gezeigt, dass durchschnittlich 5,7% der Zeit in C ++ - Programmen (und bis zu ~ 50%) für den Aufruf virtueller Funktionen (z. B. vtables + thunks) aufgewendet wurden. Später arbeitete er mit einigen Smalltalk-Forschern in der Java HotSpot-VM zusammen, um diese Probleme in OO zu lösen. Einige dieser Funktionen werden nach C ++ zurückportiert (z. B. "geschützt" und Ausnahmebehandlung).
Wie bereits erwähnt, ist C ++ statisch typisiert, während Objective C ententypisch ist. Der Leistungsunterschied bei der Ausführung (jedoch nicht bei Codezeilen) ist wahrscheinlich auf diesen Unterschied zurückzuführen.
quelle
Diese Studie besagt, dass Sie C verwenden müssen, um die Leistung in einem CPU-intensiven Spiel wirklich zu erzielen. Der verlinkte Artikel enthält ein XCode-Projekt, das Sie ausführen können.
Ich glaube, das Fazit lautet: Verwenden Sie Objective-C, wo Sie mit den Funktionen des iPhones interagieren müssen (schließlich kann es für niemanden gut sein, überall Trampoline zu platzieren ), aber wenn es um Schleifen, Dinge wie Vektorobjektklassen oder Intensiv geht Array-Zugriff, bleiben Sie bei C ++ STL- oder C-Arrays, um eine gute Leistung zu erzielen.
Ich meine, es wäre total albern zu sehen
position = [[Vector3 alloc] init] ;
. Sie fragen nur nach einem Leistungstreffer, wenn Sie Referenzzählungen für Basisobjekte wie einen Positionsvektor verwenden.quelle
Ja. c ++ ist in Bezug auf Leistung / Ausdruck / Ressourcenkompromiss oberstes Gebot.
"Ich suche nach harten Daten, nicht nach Evangelisation". Google ist dein bester Freund.
obj-c nsstring wird von Apple Enginneers für die Leistung gegen c ++ ausgetauscht. In Geräten mit eingeschränkten Ressourcen wird sie nur von c ++ als MAINSTREAM-Sprache abgeschnitten. NSString stringWithFormat ist langsam
Die obj-c oop-Abstraktion wird für die Leistung in prozedurale c-Strukturen dekonstruiert, andernfalls ist eine MAGNITUDE-Reihenfolge langsamer als Java! Dem Autor ist auch das Zwischenspeichern von Nachrichten bekannt - aber kein Problem. Das Modellieren vieler kleiner Spieler- / Feindobjekte erfolgt also in oop mit c ++ oder in vielen prozeduralen Strukturen mit einem einfachen OOP-Wrapper mit obj-c. Es kann ein Paradigma geben, das Prozedural + Objektorientierte Programmierung = obj-c gleichsetzt. http://ejourneyman.wordpress.com/2008/04/23/writing-a-ray-tracer-for-cocoa-objective-c/
quelle