Was sind die häufigsten Ursachen für die hohe CPU-Nutzung?
Hintergrund:
In meine Anwendung in C++ geschrieben, die ich erstellt habe, 3 threads:
- AnalysisThread (oder Hersteller) : es liest eine Eingabedatei, analysiert es und erzeugt Muster, und enqueue in
std::queue
1. - PatternIdRequestThread (oder Verbraucher) : es deque Muster aus der Warteschlange und sendet Sie nacheinander auf die Datenbank über einen client (geschrieben in C++), das gibt Muster uid das ist dann zugeordnet, um die entsprechenden Muster.
- ResultPersistenceThread : es braucht noch einige Dinge, Gespräche zur Datenbank, und es funktioniert gut wie erwartet, so weit wie CPU-Auslastung betroffen ist.
Ersten beiden threads nehmen 60-80% CPU-Auslastung, jede dauert etwa 35% im Durchschnitt.
Frage:
Ich verstehe nicht, warum manche threads nehmen hohe CPU-Auslastung.
Analysiere ich es wie folgt : wenn es das OS, wer trifft Entscheidungen, wie Kontext-switchunterbrechenund Planung zu welchem thread sollte Zugang zu system-Ressourcen, wie CPU-Zeit, dann kommen wie einige threads in einem Prozess geschehen, um mehr CPU als die anderen? Es sieht aus wie einige threads gewaltsam nimmt die CPU aus dem OS mit vorgehaltener Waffeoder das OS hat eine echte Schwäche für einige threads und so ist es voreingenommen gegenüber Sie von Anfang an, geben Ihnen alle Ressourcen, die es hat. Warum kann Sie nicht unparteiisch sein, und geben Sie Ihnen alle gleich?
Ich weiß, es ist naiv. Aber bin ich verwirrt mehr, wenn ich denke, dass entlang dieser Linie : der OS ermöglicht den Zugriff auf die CPU an einen thread, bezogen auf die Menge der Arbeit durch den thread, aber wie sieht das OS berechnen oder Vorhersagen, die Menge der Arbeit vor Ausführung komplett?
Ich Frage mich, was sind die Ursachen für die hohe CPU-Nutzung? Wie können wir Sie erkennen? Ist es möglich, Sie zu identifizieren, einfach durch einen Blick auf den code? Was sind die Werkzeuge?
Ich bin mit Visual Studio 2010.
1 ist. Ich habe meine Zweifel std::queue
als gut. Ich weiß, dass die standard-Container sind nicht thread-sicher. Aber wenn genau ein thread enqueue items to queue, dann ist es sicher, wenn genau ein thread deque-Elemente aus? Ich kann mir vorstellen es ist wie ein Rohr, auf der einen Seite, die Sie einfügen von Daten, auf der anderen, entfernen Sie Daten, dann warum sollte es unsicher sein wenn es fertig ist simultenously? Aber das ist nicht die eigentliche Frage in diesem Thema, aber Sie können fügen Sie einen Hinweis in Ihrer Antwort, die Bewältigung dieser.
Updates:
Nachdem ich gemerkt habe, dass meine consumer-thread war mit busy-spin, das habe ich behoben mit Schlafen für 3 Sekunden. Dieses Update ist nur vorübergehend, und bald werde ich verwenden Event statt. Aber auch mit Schlafendie CPU-Nutzung sank um 30-40%, und gelegentlich geht es bis zu 50%, das scheint nicht erwünscht zu sein, aus der usability-Sicht, wie das system reagiert nicht auf die anderen Anwendungen, in denen der Benutzer derzeit arbeitet.
Gibt es eine Möglichkeit, die ich noch verbessern könnte an der hohen CPU-Auslastung? Wie bereits gesagt, die Produzenten-thread (was nutzt nun die meisten CPU-Zyklen) liest eine Datei ein, analysiert die Pakete (von einigen-format) und erzeugt Muster aus Ihnen. Wenn ich Schlaf, dann die CPU-Auslastung verringern würde, aber würde es eine gute Idee sein? Was sind die häufigsten Wege um es zu lösen?
InformationsquelleAutor der Frage Nawaz | 2012-02-14
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich persönlich wäre ziemlich genervt, wenn meine threads hatte Arbeit zu tun, und es gab idle Kerne auf meinem Rechner, weil das OS war nicht indem Sie Ihnen eine hohe CPU-Auslastung. Also ich weiß nicht wirklich sehen, es gibt hier ein problem [Edit: stellt sich heraus, Ihr busy-Schleife ist ein problem, aber im Prinzip gibt es nichts falsch mit der hohen CPU-Auslastung].
OS/scheduler ziemlich viel nicht Vorhersagen, die Menge an Arbeit, die ein thread zu tun. Ein thread ist (über-Vereinfachung) in einem von drei Zuständen:
Den scheduler wählen Sie so viele Dinge laufen, wie es Kerne (oder Hyper-Threads, was auch immer), und führen Sie jeweils entweder bis er blockiert wird oder bis eine beliebige Zeitspanne nennt man ein "timeslice" abläuft. Dann wird es Zeitplan etwas anderes, wenn es kann.
So, wenn ein thread verbringt die meiste seiner Zeit in die Berechnung statt der Sperrung, und wenn es einen Kern frei, dann belegt viel CPU-Zeit.
Es gibt eine Menge von Details in wie der scheduler wählt, welche ausgeführt werden, basierend auf Dinge wie Priorität. Aber die grundlegende Idee ist, dass ein thread mit einer Menge zu tun, muss nicht vorhergesagt werden als compute-schwer, es wird halt immer verfügbar sein, wenn Sie etwas braucht Planung, und daher tendieren dazu geplant.
Für Ihre Beispiel-Schleife, wird der code nicht wirklich etwas tun, so würden Sie brauchen, um zu überprüfen, wie es wurde optimiert, vor der Beurteilung, ob die 5-7% CPU Sinn macht. Idealerweise auf einem zwei-Kern-Maschine Verarbeitung-schweren thread sollte besetzen 50% CPU. Auf einem 4-core-Maschine, 25%. Also, wenn Sie mindestens 16 Kerne, dann wird Ihr Ergebnis ist auf den ersten Blick anomalen (und wenn Sie schon 16 Kerne, dann einen thread zu besetzen 35% würden sogar mehr anomale!). In einem standard-desktop-OS die meisten Kerne im Leerlauf sind die meisten der Zeit, also je höher der Anteil der CPU, die Ihre aktuellen Programme besetzen, wenn Sie laufen, desto besser.
Auf meinem Rechner, die ich regelmäßig traf einen Kern im Wert von CPU verwenden, wenn ich einen code auszuführen, der meist Parsen von text.
Nein, das ist nicht sicher für
std::queue
mit einem standard-container.std::queue
ist ein thin wrapper auf der Oberseite des Sequenz-container (vector
deque
oderlist
), es doesn ' T fügen Sie keine thread-Sicherheit. Der thread, fügt Elemente und der thread, der Elemente entfernt ändern Sie einige Daten im gemeinsamen, zum Beispiel diesize
Feld der zugrunde liegenden container. Sie müssen entweder einige Synchronisation, oder sonst ein safe lock-free queue-Struktur, die sich auf atomarer Zugriff auf die gemeinsamen Daten.std::queue
hat weder.InformationsquelleAutor der Antwort Steve Jessop
Bearbeiten: Ok, da man sich mit beschäftigt, spin-block in der Warteschlange, das ist wahrscheinlich die Ursache für die hohe CPU-Auslastung. Das OS ist unter dem Eindruck, dass Ihre threads tun, nützliche Arbeit, wenn Sie eigentlich nicht, also bekommen Sie auch die volle CPU-Zeit. Es war eine interessante Diskussion, hier: Welche ist besser für die Leistung zu überprüfen, andere threads boolean in java
Ich rate Ihnen, wechseln Sie entweder auf Ereignisse oder auf andere blockierenden Mechanismen oder eine synchronisierte queue statt und sehen, wie es geht.
Sich auch, dass die Argumentation über die Warteschlange als " thread-safe ", da nur zwei threads sind, es zu benutzen" ist sehr gefährlich.
Vorausgesetzt die Warteschlange ist implementiert als verkettete Liste vorstellen, was passieren kann, wenn es nur ein oder zwei Elemente übrig sind. Da haben Sie keine Möglichkeit der Steuerung der relativen Geschwindigkeiten von Erzeuger und Verbraucher kann dies der Fall sein, und so sind Sie in großen Schwierigkeiten.
InformationsquelleAutor der Antwort Tudor
Bevor Sie beginnen können, darüber nachzudenken, wie optimieren Sie Ihre Fäden, um weniger zu verbrauchen CPU, die Sie benötigen, um eine Idee zu haben, wo alle, die CPU-Zeit ausgegeben. Ein Weg, um diese Informationen zu erhalten, ist die Verwendung des CPU-profiler. Wenn Sie keine haben, dann geben Sehr Schläfrig versuchen. Es ist einfach zu bedienen und kostenlos.
Dem CPU-profiler überwachen Sie Ihre Anwendung und machen Sie sich Notizen, wo die Zeit verbracht wird. Als Ergebnis wird Ihnen eine Liste der Funktionen, sortiert nach dem, wie viel CPU-Leistung, die Sie verwendet haben, während der Periode abgetastet, wie oft genannt wurden, etc. Jetzt müssen Sie sich auf die profiling-Ergebnisse ausgehend von der die meisten CPU-intensiven Funktionen und sehen, was Sie ändern können, diese zu reduzieren Sie die CPU-Auslastung.
Das wichtigste ist, dass, sobald Sie haben die profiler-Ergebnisse müssen Sie die tatsächlichen Daten, die Ihnen sagt, welche Teile der Anwendung, die Sie optimieren können, erhalten Sie die größte Rendite.
Betrachten wir nun die Arten von Dinge, die Sie finden können, die verbrauchen viel CPU.
Einen worker-thread ist typischerweise implementiert als eine Schleife. An der Spitze der Schleife wird eine Prüfung durchgeführt, um zu entscheiden, ob es Arbeit gibt, zu tun und jede verfügbare Arbeit ausgeführt wird. Eine neue iteration der Schleife beginnt der Zyklus erneut.
Finden Sie möglicherweise, dass die mit einem setup wie diesem die meisten CPU-Zeit zugeteilt wird dieser thread verbracht looping und-Prüfung, sehr wenig ausgegeben wird tatsächlich tun, ist Arbeit. Dies ist das so genannte busy-wait problem. Teilweise diese Adresse können Sie ein
sleep
zwischen schleifeniterationen, aber das ist nicht die beste Lösung. Der ideale Weg, um dieses problem zu beheben ist, um den Faden zu schlafen, wenn es keine Arbeit zu tun, und wenn einige andere Threads erzeugt Arbeit für den schlafenden thread sendet ein signal, um ihn zu wecken. Dies praktisch eliminiert die looping-overhead, der thread wird nur CPU, wenn es Arbeit zu tun. Ich in der Regel die Implementierung dieses Mechanismus mit Semaphoren, aber unter Windows kannst du auch eine Event-Objekt. Hier ist eine Skizze einer Durchführung:Beachten Sie, dass in der obigen Lösung die thread-Funktion immer versucht, schlafen zu gehen nach dem ausführen einer Aufgabe. Wenn der thread-Warteschlange weitere Arbeitsaufgaben, dann das warten auf die semaphore wird sofort zurück, da jedes mal, wenn ein Element wurde Hinzugefügt, um die Warteschlange der Urheber muss genannt wake_up () - Funktion.
Die andere Sache, die Sie sehen können, in der profiler-Ausgabe ist, dass die meisten von der CPU ausgegeben wird, in die Arbeitsweise der worker-thread, während Sie arbeiten. Das ist eigentlich keine schlechte Sache, wenn die meiste Zeit mit arbeiten verbringen, dann bedeutet das, dass der thread hatte Arbeit zu tun, und da war die CPU-Zeit zur Verfügung haben, der arbeiten, also im Prinzip gibt es nichts falsch hier.
Aber dennoch kann man nicht glücklich sein, dass Ihre Anwendung so viel CPU, so dann Sie benötigen, zu betrachten, Möglichkeiten, optimieren Sie Ihren code so, dass es nicht die Arbeit effizienter zu gestalten.
Zum Beispiel, können Sie feststellen, dass einige kleine Hilfs-Funktion aufgerufen wurde, Millionen von Zeiten, also während einer einzigen Ausführung der Funktion ist schnell, wenn Sie das multiplizieren von ein paar Millionen wird es zu einem Flaschenhals für den thread. An diesem Punkt sollten Sie sich Möglichkeiten, um Optimierungen zur Reduzierung der CPU-Auslastung in dieser Funktion, entweder durch optimieren den code, oder durch die Optimierung der Anrufer(s) zum Aufruf der Funktion weniger Zeit.
Also die Strategie hier ist, um aus der teuersten Funktion nach den profiling-Bericht und versuchen, eine kleine Optimierung. Dann führen Sie erneut den profiler, um zu sehen, wie sich die Dinge verändert. Sie können feststellen, dass eine kleine änderung, die die meisten CPU-intensive Funktion, bewegt ihn nach unten auf den 2. oder 3. Platz, und als Ergebnis die Gesamt-CPU-Auslastung reduziert wurde. Nachdem Sie beglückwünschen sich selbst für die Verbesserung, wiederholen Sie die übung mit dem neuen top-Funktion. Sie können weiterhin diesen Vorgang, bis Sie zufrieden sind, dass Ihre Anwendung so effizient wie es sein kann.
Glück.
InformationsquelleAutor der Antwort Miguel
Obwohl die anderen richtig analysiert das problem schon (so weit ich erzählen kann), lassen Sie mich versuchen, fügen Sie einige weitere Details zu den vorgeschlagenen Lösungen.
Erstens, die Zusammenfassung der Probleme:
1. Wenn Sie Ihre consumer-thread beschäftigt Spinnen in einer for-Schleife oder ähnliches, das ist eine schreckliche Verschwendung von CPU-power.
2. Wenn Sie die Funktion sleep() mit einer festen Anzahl von Millisekunden, es ist entweder eine Verschwendung von CPU, auch wenn die Zeit, die Menge ist zu gering), oder Sie verzögern das Verfahren unnötig (wenn es zu hoch ist). Es gibt keine Möglichkeit, die Zeit, Menge genau richtig.
Was Sie tun müssen, anstatt ist die Verwendung einer Art von Schlaf, wacht genau im richtigen Augenblick, D. H. wenn eine neue Aufgabe wurde an die Warteschlange.
Werde ich erklären, wie dies zu tun ist mithilfe von POSIX. Ich weiß, das ist nicht ideal, wenn Sie auf Windows, aber, von ihm zu profitieren, können Sie entweder verwenden Sie POSIX-Bibliotheken für Windows, oder verwenden Sie die entsprechenden Funktionen in Ihrer Umgebung verfügbar sind.
Schritt 1: müssen Sie eine mutex und ein signal:
Schritt 2: Nun in der consumer-thread, warten, bis das signal gesendet werden soll. Die Idee ist, dass der Hersteller sendet das signal, wenn es angehängt hat eine neue Aufgabe in die Warteschlange:
Schritt 2 oben sollte im wesentlichen in einer Endlosschleife. Stellen Sie sicher, es ist eine Möglichkeit, den Prozess zu brechen aus der Schleife. Zum Beispiel-wenn auch etwas krude-Sie können anfügen eine 'spezielle' task der Warteschlange und heißt "break aus der Schleife'.
Schritt 3: Aktivieren der Produzenten-thread zum senden ein signal, wenn es angehängt ist eine Aufgabe, die für die Warteschlange:
Schritt 4:Wenn alles fertig ist und Sie das Herunterfahren des threads, Sie müssen zerstören die mutex-und die das signal:
Schließlich lassen Sie mich zu re-iterieren, eine Sache, die die anderen schon gesagt haben: verwenden Sie nicht eine gewöhnliche
std::deque
für gleichzeitigen Zugriff. Ein Weg, dies zu lösen, ist zu erklären, noch ein weiteres mutex lock es vor jedem Zugriff auf die deque, und entsperren Sie es gleich nach.Edit: noch Ein paar Worte zu den Produzenten-threadunter Berücksichtigung der Kommentare. Soweit ich es verstehe, sind die Produzenten-thread ist derzeit frei, fügen Sie so viele Aufgaben in die Warteschlange, wie es ist. Also ich nehme an, es wird halten Sie tun, und halten Sie die CPU beschäftigt, um das Ausmaß, dass es nicht verzögert, IO und Speicherzugriff. Erstens, ich glaube nicht, dass die hohe CPU-Auslastung, die aus dieser als problem, sondern als Vorteil. Jedoch ist eine ernste Sorge ist, dass die Warteschlange wächst auf unbestimmte Zeit, möglicherweise verursacht der Prozess zum ausführen von Speicherplatz. Daher ist eine nützliche Vorsichtsmaßnahme, um zu nehmen, wäre die Begrenzung der Größe der Warteschlange, um einen angemessenen Maximalwert für die, und haben den producer-thread anhalten, wenn die Warteschlange wächst zu lang.
Um dies zu implementieren, der Produzent thread würde prüfen, ob die Länge der Warteschlange vor dem hinzufügen eines neuen Elements. Wenn es voll ist, es würde sich schlafen, warten auf ein signal gesendet werden, die von einem Endverbraucher bei der übernahme einer Aufgabe aus der Warteschlange. Für diese könnte ein sekundäres signal-Mechanismus, Analog zu der oben beschriebenen.
InformationsquelleAutor der Antwort jogojapan
Threads verbraucht Ressourcen wie Speicher. Eine Sperrung/Entsperrung thread entstehen einmalige Kosten. Wenn ein thread blockiert/verstopfte Zehntausende mal pro Sekunde diese Abfälle können erhebliche Mengen an CPU.
Aber mal ein thread blockiert ist, ist es egal, wie lange es gesperrt ist, gibt es dort keine Laufenden Kosten.
Die beliebteste Methode, um performance-Probleme ist die Verwendung von profilern.
Jedoch Tue ich dies sehr, und meine Methode ist diese: http://www.wikihow.com/Optimize-Your-Program%27s-Performance
InformationsquelleAutor der Antwort Avinash
Thread CPU-Auslastung hängt von vielen Faktoren ab, aber in der Hauptsache das OS kann nur die Zuordnung der Bearbeitungszeit basiert auf Punkte, an denen es zu unterbrechen eines thread.
Wenn Ihr thread interagiert mit der hardware sowieso dann dies verleiht dem OS eine chance zu unterbrechen und den thread zuweisen Verarbeitung anderswo, vor allem auf der Annahme beruhen, dass hardware-Interaktion benötigt Zeit. In Ihrem Beispiel verwenden Sie die iostream-Bibliothek und somit die Interaktion mit der hardware.
Wenn Ihr loop gar nicht haben, dann wäre es wahrscheinlich fast 100% cpu.
InformationsquelleAutor der Antwort ChrisBD
InformationsquelleAutor der Antwort BruceAdi
Als die Leute gesagt haben, der richtige Weg zur Synchronisierung der übergabe zwischen den Erzeuger-und Verbraucher-threads wäre, um eine Zustand-variable. Wenn der Hersteller will, fügen Sie ein element in die Warteschlange eingereiht wird, sperrt die Bedingung variable, wird das element Hinzugefügt, und Sie werden benachrichtigt Kellner auf die bedingungsvariable. Der Verbraucher wartet auf die gleiche bedingungsvariable, und wenn Sie die Meldung erhalten, verbraucht Elemente aus der Warteschlange, dann sperrt wieder. Ich würde persönlich empfehlen die Verwendung von boost::interprocess für diese, aber es kann getan werden, in einer relativ einfachen Art und Weise mit anderen APIs zu.
Auch, eine Sache im Auge zu behalten ist, dass, während konzeptionell jeder thread auf ein Ende der Warteschlange nur, die meisten Bibliotheken implementieren eine O(1)
count()
- Methode, das heißt, Sie haben eine member-variable, um die Anzahl der Elemente, und dies ist eine Gelegenheit für seltene und schwer zu diagnostizieren Parallelitätsprobleme.Wenn Sie auf der Suche nach einem Weg zu reduzieren die cpu-Nutzung von der consumer-thread (ja, ich weiß, das ist Ihre eigentliche Frage)... naja, es klingt wie es tatsächlich tut, was es soll, aber die Verarbeitung von Daten ist teuer. Wenn Sie analysieren, was es tut, kann es Möglichkeiten zur Optimierung.
Wenn Sie möchten, drosseln Sie den producer-thread intelligent... es ist ein wenig mehr Arbeit, aber hätte Sie den producer-thread hinzufügen von Einträgen in der Warteschlange, bis es einen bestimmten Schwellenwert erreicht (sagen wir 10 Elementen), dann warten Sie auf eine verschiedenen Zustand-variable. Wenn der Verbraucher verbraucht genug Daten, dass es bewirkt, dass die Anzahl der in der Warteschlange befindlichen Elemente zu gehen, unter einer Schwelle (sagen wir 5 Elemente), dann teilt er diese zweite Bedingung variable. Wenn alle Teile des Systems bewegen kann, die Daten schnell herum, dann könnte dieses noch verbraucht sehr viel CPU, aber es wäre relativ gleichmäßig unter Ihnen. Es ist an dieser Stelle, dass das OS zuständig sein sollte für die Vermietung an andere nicht Verwandte Prozesse erhalten Ihre Messe(ish) Anteil der CPU.
InformationsquelleAutor der Antwort bdow