Concurrent collections Essen zu viel cpu ohne Gewinde.Schlafen
Was wäre die korrekte Verwendung von entweder BlockingCollection
oder ConcurrentQueue
so können Sie frei dequeue Elemente ohne Sie zu verbrennen, sich die Hälfte oder mehr der CPU einen thread ?
Ich lief einige tests mit 2 threads und es sei denn, ich hatte einen Thread.Schlaf von mindestens 50~100ms würde es treffen immer mindestens 50% meiner CPU.
Hier ist ein fiktives Beispiel:
private void _DequeueItem()
{
object o = null;
while(socket.Connected)
{
while (!listOfQueueItems.IsEmpty)
{
if (listOfQueueItems.TryDequeue(out o))
{
//use the data
}
}
}
}
Mit dem obigen Beispiel würde ich ein thread.schlafen, damit die cpu nicht sprengen.
Hinweis: ich habe auch versucht es ohne, während für die IsEmpty-Prüfung, Ergebnis war das gleiche.
- Wenn Sie nichts tun, außer dequeueing dann 50% CPU-Auslastung ziemlich normal ist, im Allgemeinen mit den Threads ist es noch wichtiger, schauen Sie sich die einzelnen Kerne um die Leistung zu beurteilen.
- das klingt nicht richtig, abarbeiten der Warteschlange ist ein kleiner Betrieb. Das problem hier ist der thread sollte auf ein signal warten, um aufzuwachen, das signal sagen, es gibt etwas zu entfernen, anstatt mit einer unendlich engen Schleife zu versuchen, die Warteschlange entfernen. Das würde eine WINZIGE Menge der CPU, bei weitem nicht 50%
- Sie haben Recht, ich verpasst - war gerade auf der Suche auf die schlechte Idee, um nicht ansehen Familienmitglied Kerne!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ist es nicht, weil der
BlockingCollection
oderConcurrentQueue
, aber die while-Schleife:Natürlich wird die cpu nach unten; denn wenn die queue leer ist, dann wird die while-Schleife ist genau wie:
die wiederum fressen die cpu-Ressourcen.
Dies ist nicht ein guter Weg, mit
ConcurrentQueue
Sie verwenden solltenAutoResetEvent
mit jedem Element Hinzugefügt wird, werden Sie benachrichtigt.Beispiel:
Für eine gute Nutzung der
BlockingCollection
sollten Sie dieGetConsumingEnumerable()
warten für die Elemente Hinzugefügt werden, Wie:WaitOne
ist eine Blockierung, bis es erhält ein signal. In den code:_queueNotifier.Set();
ist das signal "hier zeigt das neue Element wird Hinzugefügt" Lesen Sie mehr aufAutoResetEvent
hier.Take
Funktion in der BlockingCollection das dient genau diesem Zweck, ohne die Notwendigkeit für die manuelle signal/wait.Sie wirklich wollen, um mit der
BlockingCollection
Klasse in diesem Fall. Es wurde entwickelt, um zu blockieren, bis ein Element in die Warteschlange. Eine Sammlung dieser Art wird oft als eine blockierende Warteschlange. Diese Art der Implementierung ist sicher für mehrere Produzenten und mehrere Verbraucher. Das ist etwas, das ist überraschend schwer zu bekommen Recht, wenn Sie versucht, es umzusetzen sich. Hier ist, was Ihr code Aussehen würde, wenn Sie verwendet werdenBlockingCollection
.Den
Take
Methode blockiert automatisch, wenn die Warteschlange leer ist. Es blockiert in einer Weise, legt den Faden in derSleepWaitJoin
Zustand, so dass es nicht verbrauchen CPU-Ressourcen. Die nette Sache überBlockingCollection
ist, dass es verwendet auch low-lock-Strategien zur Steigerung der performance. Was dies bedeutet ist, dassTake
wird überprüfen, um zu sehen, ob es ein Element in die Warteschlange und wenn nicht dann wird es kurz führen Sie eine Drehung warten, um zu verhindern, dass ein Kontext-wechseln der thread. Wenn die Warteschlange noch leer ist, dann wird der thread schlafen. Dies bedeutet, dassBlockingCollection
haben einige der performance-VorteileConcurrentQueue
bietet in Hinblick auf die gleichzeitige Ausführung.Können Sie anrufen
Thread.Sleep()
nur, wenn die Warteschlange leer ist:Ansonsten sollten Sie überlegen, um Ereignisse.