2009-10-12 8 views
7

Ich habe jetzt gemeinsame Zeiger für soem Zeit verwendet, und ich habe Leistungsprobleme in meinem Programm ... Also ich würde gerne wissen, ob gemeinsame Zeiger zu Leistungseinbußen führen. Wenn ja, wie schwer? Danke vielmals.Gemeinsame Zeiger und die Leistung

Mein Programm ist multi-threaded, mit std :: tr1 :: shared_ptr

+6

Heh. Keine Antwort hier, aber ich liebte einfach die Art, wie der Titel formuliert wurde. Ich stelle mir vor, wie die CPU munter Befehle ausführt, wenn sie plötzlich einen geteilten Zeigerbefehl an der Rückseite der Pipeline sieht. "Oh nein, das wird huuuuurt ...... OW!" –

+0

Was lässt Sie denken, dass das Problem geteilte Zeiger ist? –

+0

Leute sagen, dass sie CPU-Zeit verschwenden, das ist es: P – Guest

Antwort

4

Geteilt Zeiger Referenz gezählt sind. Insbesondere wenn Sie Multi-Threading verwenden, kann das Inkrementieren und Dekrementieren der Referenzzählung sehr viel Zeit in Anspruch nehmen. Der Grund dafür, dass Multithreading hier schmerzt, ist, dass wenn Sie einen gemeinsamen Zeiger zwischen Threads übergeben haben, die Referenzzählung zwischen diesen Threads geteilt wird, so dass jede Manipulation zwischen den Threads synchronisiert werden muss. Das kann die Dinge ziemlich verlangsamen.

Edit: Für diejenigen, die sich darum kümmern, wie viel langsamer Thread Interlocking einige ziemlich einfache Operationen machen kann, sehen Sie Herb Sutter Tests mit ein paar Implementierungen von CoW Strings. Obwohl seine Tests nicht perfekt sind (z. B. er hat nur unter Windows getestet), gibt es dennoch eine Vorstellung davon, welche Art von Verlangsamung Sie erwarten können. Für die meisten praktischen Zwecke kann/könnte man sich eine CoW-Zeichenfolge als etwas wie eine shared_ptr<charT> vorstellen, mit vielen (irrelevanten) Elementfunktionen, die hinzugefügt wurden.

+0

Dies ist nur dann der Fall, wenn Sie einen zählenden Referenzzählmechanismus verwenden. Es scheint nicht, dass dies gemäß der Dokumentation http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety – JaredPar

+2

der Fall ist. Er sagt nicht, was shared_ptr er verwendet. Einige sind bereits Thread-bewusst, andere nicht. Es ist offen zu fragen, ob der, den er benutzt, ist oder nicht. Das heißt, Sie hatten sicherlich Recht, dass die Chancen, dass dies die Ursache für ein Leistungsproblem ist, ziemlich weit entfernt sind. –

+0

Weitere Informationen hinzugefügt – Guest

10

Es ist praktisch unmöglich, diese Frage in Anbetracht der Daten richtig zu beantworten. Die einzige Möglichkeit, wirklich festzustellen, was zu einem Leistungsproblem in Ihrer Anwendung führt, besteht darin, einen Profiler auf dem Programm auszuführen und die Ausgabe zu untersuchen.

Das heißt, es ist sehr unwahrscheinlich, dass ein shared_ptr die Verlangsamung verursacht. Der shared_ptr-Typ und viele frühe Eigenentwicklungsvarianten werden in einer ständig wachsenden Anzahl von C++ - Programmen verwendet. Ich selbst benutze sie in meiner Arbeit (professionell zu Hause). Ich habe viel Zeit damit verbracht, meine Arbeitsanwendungen zu profilieren, und shared_ptr war noch nie in der Nähe eines Problems in meinem Code oder anderem Code, der in der Anwendung ausgeführt wird. Es ist viel wahrscheinlicher, dass der Fehler anderswo ist.

3

Sehr unwahrscheinlich - Sie müssten die meiste Zeit damit verbringen, Zeiger herumzureichen.

Der Effekt von shared ptrs ist normalerweise gering, und es ist schwer, sogar einen Kantenfall zu konstruieren, wo sie zu einem Problem werden (vorausgesetzt, eine korrekte Implementierung und ein richtig optimierender Compiler).

Auswirkungen des gemeinsamen ptr:

  • erhöht Zuordnungsgröße.
    Das wäre nur von Bedeutung, wenn Sie viele gemeinsame Zeiger auf sehr kleine Objekte haben (z. B. Dutzende von Millionen von shared_ptr<int>) und/oder in der Nähe eines Speicherlimits arbeiten. Es gibt ein kleines Potential für einen bemerkenswerten Leistungsabfall, wenn die zusätzlichen Zuteilungen einen Cache/NUMA Ebene innerhalb einer inneren Schleife überschreitet

  • erhöhte numer der Zuteilungen
    shared_ptr allcoates ein Verfolgungsobjekt (Referenzzählwert, schwache Zähl- und deleter) . Dies setzt den Heap unter Druck und kann eine allgemeine Verlangsamung verursachen, wenn Sie eine hohe Gesamtanzahl von Zuweisungen und Deallocations haben.
    kann mit make_shared, Putting referent und TRACKNG Objekt in eine einzige Zuordnung

  • Referenzzählung
    erhöht die Kosten für eine Kopie eines Zeigers vermieden werden. In einer Single-Thread-Anwendung würden Sie bemerken, dass nur Sie die meiste Zeit Zeit damit verbringen, Zeiger zu kopieren. In einer Multithread-Anwendung müssen Sie immer noch hohe Konflikte mit den gleichen Zeigern haben.
    Kosten der Kopie können an vielen Stellen vermieden werden, indem man eine shared_ptr<T> const & z. als Funktionsargument.

  • Dereferenzieren
    Die zusätzlichen Kosten dereferenzierenden Null in einem Release-Build eines optimierenden Compilers. Debug-Builds entsprechen oft Funktionsaufrufen und zusätzlichen NULL-Prüfungen. Vor allem in Debug-Builds müssen Sie jedoch die meiste Zeit Dereferenzierungszeiger verwenden, um einen Unterschied zu machen.


Ohne zusätzliche informaiton, können wir Ihnen nicht helfen. Sie müssen beschreiben, was die "Leistungsprobleme" sind (allgemeine Schwerfälligkeit, bestimmte Vorgänge, die lange dauern, viel Austausch), und einige Schlüsselzahlen - was Ihre App tut, wie viele intelligente Zeiger es gibt, wie oft sie kopiert werden, und welche anderen Operationen du besindse, jonglierst intelligente Zeiger.

Oder Sie lernen, Leistungsüberwachung und/oder einen Profiler zu verwenden, um herauszufinden, was die Verlangsamungen verursacht und ob es bestimmte Engpässe gibt.

5

Wenn Ihr Programm scheint, ein Leistungsproblem zu haben, ist es ganz natürlich, zu raten, was das Problem sein könnte, aber wenn Sie eine Wette platzieren möchten, ist es fast 100% wahrscheinlich, etwas ganz anderes zu sein. Profiling kann das Problem finden. This is the method I use.

0

Eine Sache, die die Leistung beeinträchtigen könnte, ist die übermäßige Weitergabe von shared_ptr als Funktionsparameter. Eine Lösung dafür wäre, Referenzen auf shared_ptr zu übergeben. Doch diese Mikro-Optimierung ist, so tun es nur, wenn es wirklich

benötigt

edit: Wenn darüber nachgedacht, es gibt bessere Möglichkeiten zur Optimierung:

  • Wenn übermäßige den Zeiger vorbei, sollten Sie wahrscheinlich lassen das Objekt tut etwas, anstatt es herumzuziehen.
  • Sie können (const) Verweis auf die Stelle des
  • passieren einen Verweis auf den Zeiger Zeiger-Objekt übergeben, wenn der Zeiger
0

geändert werden muss Sie über die Leistung nicht erraten: Profile Code.

12

Wenn Ihre App 700-Byte-XML-Nachrichten übergibt, die in 65-Byte-Google-Protokollnachrichten oder 85-Byte-ASN.1-Nachrichten enthalten sein könnten, spielt das wahrscheinlich keine Rolle. Aber wenn es eine Million etwas pro Sekunde verarbeitet, dann würde ich die Kosten für das Hinzufügen von 2 vollen Lese-Änderungsschreib- (RMW-) Zyklen zum Übergeben eines Zeigers nicht verwerfen.

Ein voller Lese-Modifikations-Schreibvorgang liegt in der Größenordnung von 50 ns, also sind zwei 100 ns. Diese Kosten sind die Kosten eines Lock-Inc und eines Lock-Dec - das gleiche wie 2 CAS's. Dies ist die Hälfte eines Windows-kritischen Abschnitts Reserve und Release.Dies wird verglichen mit einem einzigen Maschinenzyklus-Push (400 PICO Sekunden auf einer 2,5 GHz-Maschine)

Und dies beinhaltet nicht einmal die anderen Kosten für das Ungültigmachen der Cache-Zeile, die tatsächlich die Zählung enthält, die Auswirkungen der BUS-Sperre auf anderen Prozessoren usw. usw.

Smart Zeiger durch const Referenz übergeben ist fast immer zu bevorzugen. Wenn der Angerufene keinen neuen geteilten Zeiger erstellt, wenn er die Lebensdauer des Pointees garantieren oder kontrollieren will, dann ist es ein Fehler im aufgerufenen. Willy-Nilly Passing Thread sichere Referenz Zählen intelligente Zeiger um Wert läuft nur nach Leistung Treffer fragen.

Die Verwendung von Referenz gezählten Zeigern vereinfacht die Lebensdauer zweifellos, aber freigegebene Zeiger nach Wert zu übergeben, um sich gegen Defekte im Angerufenen zu schützen, ist schierer und völliger Unsinn.

Übermäßige Verwendung der Referenzzählung kann in Kürze ein schlankes Programm, das 1 mm Nachrichten pro Sekunde (mps) verarbeiten kann in eine fette, die 150 k mps auf der gleichen Hardware verarbeitet. Plötzlich braucht man ein halbes Rack Server und 10000 $ Strom pro Jahr.

Sie sind immer besser dran, wenn Sie die Lebensdauer Ihrer Objekte ohne Referenzzählung verwalten können.

Ein Beispiel für eine einfache Verbesserung ist, sagen wir, wenn Sie ein Objekt fächern und Sie wissen, dass die Breite des Fanouts (sagen wir n) um n erhöht wird, anstatt einzeln bei jedem Fanout zu erhöhen.

BTW, wenn die CPU ein Lock-Präfix sieht, sagt es wirklich "Oh nein das wird weh tun".

Alles was gesagt wird, ich stimme allen zu, dass Sie den Hot Spot überprüfen sollten.