Ich weiß nicht, ob die Frage dumm ist oder nicht, Sperren und der Monitor ist eine Art Black Box für mich.
Aber ich habe es mit einer Situation zu tun, in der ich entweder das gleiche Sperrobjekt verwenden kann, um alles ständig zu sperren, oder eine unbestimmte Anzahl von Objekten, um auf einer feineren Körnungsebene zu sperren.
Ich weiß, dass der zweite Weg die Sperrkonflikte verringern wird, aber ich könnte 10K Objekte als Locks benutzen und ich weiß nicht, ob es Auswirkungen hat oder nicht.
Bottom line: Schaden zu viele Sperren oder hat es keine Auswirkungen?
Bearbeiten
Ich habe eine Lib geschrieben, die einen Graphen von Objekten verwaltet, die Zahl könnte sehr hoch sein. Im Moment ist es nicht threadsicher, hauptsächlich aus dem Grund, den Eric in seinem Kommentar angegeben hat.
Ich dachte anfangs, dass wenn der Benutzer etwas Multithreading machen möchte, er / sie sich um das Sperren kümmern müsste.
Aber jetzt frage ich mich, ob ich es threadsicher machen müsste, was wäre der beste Weg, dies zu tun (beachten Sie, dass es für mich nicht so einfach und schnell ist, es threadsicher zu machen) Testen beider Lösungen ist etwas, was ich nicht leicht machen kann)?
Da das Ziel darin besteht, jedes Objekt des Diagramms threadsicher zu machen, könnte ich die Instanz des Objekts für die Sperre verwenden, wenn ich auf seine Eigenschaften zugreifen / sie ändern möchte. Ich weiß, es ist der beste Weg, Konflikte zu reduzieren, aber ich weiß nicht, ob es so viel skalieren würde, als nur eine Sperre für den gesamten Graphen zu haben.
Ich weiß, dass es eine Menge zu berücksichtigen gibt, wie viele Threads und vor allem (glaube ich) die Chance, dass ein Objekt von mehreren Threads gleichzeitig aufgerufen / geändert wird (was ich für ziemlich niedrig halte). Aber ich kann in einem solchen Fall keine genauen Informationen über Sperren und deren Overhead finden.
Um eine bessere Übersicht über die Vorgänge zu erhalten, habe ich mir den Quellcode der Monitor
-Klasse und deren C ++ - Pendant in clr/src/vm/syncblk.cpp
in der von Microsoft freigegebenen Gemeinsamen Quell-Common-Language-Infrastruktur angesehen .
Um meine eigene Frage zu beantworten: Nein, eine Menge Schlösser zu haben tut mir nicht weh in irgendeiner schädlichen Art, die mir einfällt.
Was ich gelernt habe:
1) Eine Sperre, die bereits vom selben Thread übernommen wurde, wird "fast frei" verarbeitet.
2) Eine Sperre, die zum ersten Mal genommen wird, ist im Grunde die Kosten von InterlockedCompareExchange
.
3) Mehrere Threads, die auf eine Sperre warten, sind relativ kostengünstig zu verfolgen (eine Linkliste wird beibehalten, O (1) Komplexität).
4) Ein Thread, der darauf wartet, dass eine Sperre ausgelöst wird, ist bei weitem der teuerste Anwendungsfall, die erste Drilltests versuchen, auszusteigen, aber wenn es nicht genug ist, wird ein Threadwechsel stattfinden und den Thread in den Ruhezustand versetzen Mutex signalisiert, dass es Zeit ist aufzuwachen wegen der Lock Release.
Ich habe meine Antwort gefunden, indem ich nach den 2) gegraben habe: Wenn Sie immer mit demselben Objekt oder einem anderen 10K sperren, ist es im Grunde dasselbe (zusätzliche Initialisierung wird durchgeführt, wenn Sie ein bestimmtes Objekt zum ersten Mal sperren) schade). InterlockedCompareExchange ist nicht daran interessiert, am selben oder an einem anderen Speicherort (AFAIK) aufgerufen zu werden.
Die Auseinandersetzung ist bei weitem das wichtigste Anliegen. Viele Sperren zu haben, würde (in meinem Fall drastisch) die Wahrscheinlichkeit einer Konkurrenz reduzieren, also kann es nur eine gute Sache sein.
1) ist auch eine wichtige gelernte Lektion: Wenn ich für jede Eigenschaft Änderung / Zugang sperren / entsperren kann ich Leistungen verbessern, indem ich zuerst das Objekt sperre, dann viele Eigenschaften ändere und die Sperre freigebe. Auf diese Weise gibt es nur einen InterlockedCompareExchange und das Sperren / Entsperren innerhalb der Implementierung der Eigenschaft Änderung / Zugriff erhöht nur einen internen Zähler.
Um tiefer zu graben, müsste ich mehr Informationen über die Implementierung von InterlockedCompareExchange finden, ich denke, es hängt von der CPU-spezifischen Assembler-Anweisung ab ...
In der Regel sind Performance-Probleme beim Sperren mit Konflikten verbunden. Das Erlangen einer unbestätigten Sperre liegt in der Größenordnung von 10 Nanosekunden. Contention ist der wahre Leistungskiller. Wie Sie betonen, kann eine höhere Anzahl an Sperren (höhere Granularität der Sperren) die Leistung verbessern, indem Konflikte verringert werden.
Der Nachteil von mehreren Sperren ist, dass die Sperrverwaltung in der Regel komplexer sein muss. Wenn mehrere Sperren erforderlich sind, um eine Operation durchzuführen, besteht die erhöhte Möglichkeit von Ressourcenknappheitsproblemen wie Deadlock oder Livelock. Eine ordnungsgemäße Sperrverwaltung, z. B. das Erzwingen der Reihenfolge der Sperrenerfassung, kann diese Probleme beheben.
Ohne weitere Details würde ich wahrscheinlich mit einer Sperre gehen, da die Implementierung einfacher ist und die Leistung meiner Anwendung genau überwacht wird. Insbesondere gibt es .NET-Leistungsindikatoren, die sich auf Sperrkonflikte beziehen, die bei der Diagnose / Erkennung von Problemen mit der Sperrenkonfliktproblematik helfen können.
Wie bei allen leistungsbezogenen Antworten möchte ich auf diesen außergewöhnlichen Blogpost von Eric Lippert , es kommt darauf an. Schau dir seine sechs Fragen an, was sind die Antworten in deinem Fall? Versuchen Sie, was während Ihrer Bedingungen passiert.
Anzahl der Kerne, Konkurrenz, Caching usw., alle Angelegenheiten, also sehen Sie, was für Sie in Ihrem Fall passiert, es ist wirklich unmöglich vorher zu wissen.
Für diejenigen, die nicht auf den Link klicken; Führe die Pferde !
Ich spreche hier nicht von Leistung, sondern von Geschwindigkeit, sondern davon, was passiert, wenn die Anwendung eine Weile läuft. Laut Lock (Monitor) interne Implementierung in .NET die Monitor-Implementierung ist ziemlich Smart in .NET, so dass die internen Sperren für jedes Objekt einen realisierbaren Ansatz zu sein scheinen, da Sie Objekte in den Zehntausenden und nicht Millionen angegeben haben.
Bottom line: Schaden zu viele Sperren oder hat es keine Auswirkungen?
Nicht für sich allein, aber es könnte ein Grund sein, sich die Architektur Ihres Programms anzuschauen. Wenn Sie mehrere Milliarden Objekte gleichzeitig sperren, verursacht das Overhead.
Tags und Links .net c# multithreading