Nachfolgend finden Sie eine Implementierung einer ineinandergreifenden Methode, die auf basiert Interlocked.CompareExchange
.
Ist es ratsam, dass dieser Code SpinWait
vor dem Wiederholen einen Spin verwendet?
public static bool AddIfLessThan(ref int location, int value, int comparison)
{
int currentValue;
do
{
currentValue = location; // Read the current value
if (currentValue >= comparison) return false; // If "less than comparison" is NOT satisfied, return false
}
// Set to currentValue+value, iff still on currentValue; reiterate if not assigned
while (Interlocked.CompareExchange(ref location, currentValue + value, currentValue) != currentValue);
return true; // Assigned, so return true
}
Ich habe SpinWait
in diesem Szenario verwendet gesehen, aber meine Theorie ist, dass es unnötig sein sollte. Immerhin enthält die Schleife nur eine Handvoll Anweisungen, und es gibt immer einen Thread, der Fortschritte macht.
Angenommen, zwei Threads rennen um diese Methode, und der erste Thread ist sofort erfolgreich, während der zweite Thread zunächst keine Änderung vornimmt und wiederholt werden muss. Ist es ohne andere Konkurrenten überhaupt möglich, dass der zweite Thread beim zweiten Versuch fehlschlägt ?
Wenn der zweite Thread des Beispiels beim zweiten Versuch nicht fehlschlagen kann, was können wir dann mit einem gewinnen SpinWait
? In dem unwahrscheinlichen Fall, dass hundert Fäden um die Durchführung der Methode rennen, einige Zyklen abschneiden?
SpinOnce
, um zu verhindern, dass ein Single-Thread-Betriebssystem möglicherweise ausgehungert wird. Siehe stackoverflow.com/questions/37799381/…Interlocked
. Zur Verdeutlichung interessiert mich nur, ob aSpinWait
sinnvoll ist oder nicht , um beispielsweise CPU-Zyklen sinnvoll zu speichern oder (danke @MatthewWatson!) Zu verhindern, dass ein Single-Thread-Betriebssystem ausgehungert wird.SpinWait
nicht einmal den Stromverbrauch senkt, da ohnehin die gleiche Anzahl von Versuchen durchgeführt wird! (Mit zwei Threads ist das ein Versuch für den ersten und zwei für den zweiten Thread.)Antworten:
Meine nicht-Expertenmeinung ist, dass in diesem speziellen Fall, in dem gelegentlich zwei Threads aufgerufen werden
AddIfLessThan
, aSpinWait
nicht benötigt wird.AddIfLessThan
Dies könnte von Vorteil sein, wenn beide Threads in einer engen Schleife aufgerufen werden, sodass jeder Thread einige μs lang ohne Unterbrechung Fortschritte machen kann.Eigentlich habe ich ein Experiment durchgeführt und die Leistung eines Threads gemessen, der
AddIfLessThan
in einer engen Schleife aufgerufen wird , im Vergleich zu zwei Threads. Die beiden Threads benötigen fast viermal mehr, um die gleiche Anzahl von Schleifen (kumulativ) zu erstellen. Durch Hinzufügen von aSpinWait
zur Mischung werden die beiden Threads nur geringfügig langsamer als der einzelne Thread.quelle
SpinWait
innerhalb derAddIfLessThan
Methode, und obwohl es sich um einen Werttyp handelt und seineSpinOnce
Methode nie aufgerufen wird, fügt sie dennoch etwas Overhead hinzu.Zwei Themen sind einfach kein
SpinWait
Diskussionsthema. Dieser Code sagt uns jedoch nicht, wie viele Threads tatsächlich um die Ressource konkurrieren können, und bei relativ hoher Anzahl von Threads hat die Verwendung vonSpinWait
vorteilhaft sein. Insbesondere bei einer höheren Anzahl von Threads wird die virtuelle Warteschlange von Threads, die versuchen, die Ressource erfolgreich zu erfassen, länger, und diejenigen Threads, die am Ende zufällig bedient werden, haben gute Chancen, ihre vom Scheduler zugewiesene Zeitscheibe zu überschreiten, was wiederum möglich ist führen zu einem höheren CPU-Verbrauch und können die Ausführung anderer geplanter Threads auch mit höherer Priorität beeinträchtigen. DasSpinWait
hat eine gute Antwort auf diese Situation, indem eine Obergrenze für zulässige Drehungen festgelegt wird, nach der die Kontextumschaltung ausgeführt wird. Es ist also ein vernünftiger Kompromiss zwischen der Notwendigkeit, einen teuren Systemaufruf durchzuführen, um eine Kontextumschaltung auszulösen, und dem unkontrollierten CPU-Verbrauch im Benutzermodus, der in bestimmten Situationen die Ausführung anderer Threads beeinträchtigen kann.quelle
SpinWait
Overkill macht, oder nicht?SpinWait
ist die bessere Strategie (mit relativ geringen Kosten von Dutzenden von Mikrosekunden) als die Nichtanwendung, es sei denn, Sie schließen im Voraus die Möglichkeit von Szenarien mit hoher niedriger Last aus, um einen Lastpunkt zu finden, an dem der Durchsatz möglich ist Betroffen zu sein würde Ihnen einen Hinweis geben, ob Sie es brauchen oder nicht (beachten Sie, dass es auch von der Anzahl der Kerne abhängen kann).SpinWait
Mehrwert entsteht. Bisher scheinen dies (A) der Single-Core-Fall und (B) möglicherweise der sehr umstrittene Fall zu sein.