Kosten von Std :: Mutex vermeiden, wenn kein Multi-Threading ist?

9

Angenommen, ich habe eine Anwendung, die möglicherweise mehrere Threads erzeugt hat oder nicht. Lohnt es sich, Operationen zu schützen, die eine Synchronisation mit einem std :: mutex benötigen, wie unten gezeigt, oder ist die Sperre so günstig, dass sie beim Single-Threading keine Rolle spielt?

%Vor%

Bearbeiten

Danke an alle, die geantwortet und kommentiert haben, sehr interessante Diskussion.

Ein paar Klarstellungen:

Die Anwendung verarbeitet Eingabefelder und entscheidet für jedes Chunk, ob es in einer single-threaded oder parallel oder anderweitig gleichzeitig verarbeitet wird. Es ist nicht unwahrscheinlich, dass kein Multithreading benötigt wird.

Das operation_requiring_synchronization() besteht normalerweise aus ein paar Einfügungen in globale Standardcontainer.

Profiling ist natürlich schwierig, wenn die Anwendung plattformunabhängig ist und unter einer Vielzahl von Plattformen und Compilern (Vergangenheit, Gegenwart und Zukunft) gut funktionieren sollte.

Aufgrund der bisherigen Diskussion tendiere ich zu der Ansicht, dass sich die Optimierung lohnt.

Ich denke auch, dass std::atomic<bool> more_than_one_thread_active wahrscheinlich zu einem nicht-atomaren bool multithreading_has_been_initialized geändert werden sollte. Die ursprüngliche Idee war, die Flagge wieder ausschalten zu können, wenn alle Threads außer dem Hauptdorm inaktiv sind, aber ich sehe, wie dies fehleranfällig sein könnte.

Die explizite Bedingung in einen angepassten lock_guard zu abstrahieren, ist eine gute Idee (und erleichtert zukünftige Änderungen des Designs, einschließlich der einfachen Rückkehr zu std :: lock_guard, wenn die Optimierung sich nicht lohnt).

    
FaulerHase 31.08.2015, 18:13
quelle

6 Antworten

10

Im Allgemeinen sollten Optimierungen nur dann durchgeführt werden, wenn in Ihrem spezifischen Anwendungsfall kein Bedarf besteht, wenn sie die Gestaltung oder Organisation von Code beeinflussen. Das liegt daran, dass diese Art von algorithmischen Optimierungen später sehr schwierig sein kann. Point-Micro-Optimierungen können immer später hinzugefügt werden und sollten aus verschiedenen Gründen vor dem Bedarf vermieden werden:

  1. Wenn Sie den typischen Anwendungsfall falsch einschätzen, können sie die Leistung sogar verschlechtern.

  2. Sie können das Debuggen und Pflegen von Code erschweren.

  3. Auch wenn Sie den Anwendungsfall richtig einschätzen, können sie auf neuen Plattformen die Leistung verschlechtern. Zum Beispiel ist die Mutex-Akquisition in den letzten acht Jahren um mehr als eine Größenordnung billiger geworden. Kompromisse, die heute sinnvoll sind, könnten morgen keinen Sinn ergeben.

  4. Sie können Zeit damit verschwenden, unnötige Dinge zu verschwenden, und noch schlimmer, Sie können Zeit verschwenden, die für andere Optimierungen benötigt wird. Ohne große Erfahrung ist es sehr schwierig vorherzusagen, wo die tatsächlichen Engpässe in Ihrem Code liegen werden, und selbst Experten sind oft überrascht, wenn sie tatsächlich Profile erstellen.

Dies ist eine klassische Punkt-Mikro-Optimierung, also sollte es nur gemacht werden, wenn das Profiling einen wahrscheinlichen Nutzen zeigt.

    
David Schwartz 31.08.2015 21:35
quelle
7

Ja, es lohnt sich .

Unter Ihrer Frage hat David Schwarz kommentiert:

  

Ein unangekündigter Mutex ist fast frei. Die Kosten für if sind wahrscheinlich vergleichbar.

Das ist eklatant falsch (aber ein häufiges Missverständnis).
Versuchen Sie Folgendes:

%Vor%

Meine Ausgabe? (Visual C ++)

  

bedingt: 24 ms, total = 3684292139
  Unbedingt: 845 ms, gesamt = 3684292139

    
Mehrdad 31.08.2015 18:59
quelle
2

Sie sind auf dem richtigen Weg - schreiben Sie den funktionalen Teil ohne Synchronisation und fügen Sie ihn extern hinzu, wenn und benötigt wird.

Anstelle des expliziten if -Blocks würde ich immer noch die Sperre instantiieren und die Komplexität dort verstecken.

%Vor%

Und die letzte Note - wenn du sowieso eine atomare Flagge hast, kannst du sie einfach in einen Spinlock verwandeln und deine Logik einfacher halten.

    
bobah 31.08.2015 22:49
quelle
0

Ich stimme nicht mit der weit verbreiteten Idee überein, dass das Sperren von Mutext billig ist. Wenn Sie wirklich nach Leistung sind, würden Sie dies nicht tun wollen.

Mutexes (sogar unangefochten) treffen dich mit drei Hummern: sie bestrafen Compiler-Optimierungen (Mutexe sind Optimierungsbarrieren), sie behindern Speicherzäune (auf unpessimierten Plattformen) und sie sind Kernel-Aufrufe. Also, wenn Sie nach Nanosekunden Leistung in engen Schleifen sind, ist es eine Überlegung wert.

Die Verzweigung ist auch nicht großartig - aus mehreren Gründen. Die wirkliche Lösung besteht darin, Operationen zu vermeiden, die eine Synchronisation in Multithread-Umgebungen erfordern. So einfach ist das.

    
SergeyA 31.08.2015 18:49
quelle
0

Ja, oft wird die Vermeidung einer unnötigen Sperre mit einem Conditional die Performance verbessern, einfach weil ein Mutex normalerweise auf ein RMW angewiesen ist oder in den Kernel eintritt, was für einen einfachen Zweig relativ teuer ist. Im doppelt angekreuzten Sperr-Idiom finden Sie ein Beispiel für ein anderes Szenario, in dem die Vermeidung von Sperren hilfreich sein kann.

Sie möchten jedoch immer die Kosten in Betracht ziehen, um davon zu profitieren. Multi-Threading-Fehler können sich beim Starten eines speziellen Gehäuses für Einzel- und Multithread-Code einschleichen, die zum Aufspüren saugen können. Die andere Sache, die es zu beachten gilt, ist, dass es zwar einen messbaren Unterschied zwischen dem Sperren des Locks geben kann und nicht, dass dies jedoch keinen messbaren Einfluss auf die Software als Ganzes hat. Also messen, aber intelligent messen.

    
Jason 31.08.2015 21:32
quelle
0

Im Allgemeinen ist es möglich, dass es billig genug ist, sich nicht darum zu kümmern, bis Sie fertig sind

Wenn Sie fertig sind, können Sie es in beide Richtungen profilieren und die Auswirkungen sehen.

Denken Sie daran, dass Sie den Effekt für Single- und Multi-Threading profilieren müssen. Es kann auch Multi-Threaded wirken.

%Vor%

Sie sollten erwägen, dies als Option für die Kompilierung zu betrachten, und eine binäre und multi-threaded Version Ihrer Binärdatei zu haben, so dass keine if benötigt wird

%Vor%

Fast jeder Optimierer entfernt Code, der von einem const bool umgeben ist, basierend auf seinem Wert

    
Glenn Teitelbaum 31.08.2015 18:52
quelle

Tags und Links