Benutzer mit den meisten Antworten
Schleife pausieren, wegen CPU ausgelastet

Frage
-
Hi,
ich habe das folgende Problem mit einer While-Schleife:
Die Schleife wird ausgeführt, und ist endlich - allerdings wird sie ca. 315Mio mal durchlaufen.
Mit DoEvents habe ich es hinbekommen, dass das Programm nicht 'einfriert', aber die CPU-Last ist auf 100% (zumindest der Kern, in dem das Prog. läuft).
Wie bekomme ich es hin, eine kurze Pause zu machen, nach einer bestimmten Anzahl an durchläufen?
Threading.Thread.Sleep(n) möchte ich nicht nutzen, außerdem bringt das nichts für die Auslastung.
Hier ein Teil meines Codes:
While _array(0) <= _end + 1 ikx += 1 'Anweisungsblöcke 'blablabla 'blablabla ' ... If ikx >= 100000 Then Application.DoEvents() ikx = 0 End If End While
Vielen Dank im voraus.
Antworten
-
Hallo,
wenn Dein Laptop schlecht gekühlt wird, so lässt sich das durch Dein Programm bedingt beeinflussen.
Auf Programmseite kannst Du am ehesten Einfluss darauf nehmen, in dem Du den Algorithmus optimierst.Das Betriebssystem ist darauf ausgelegt, alle anfallende Arbeit so schnell wie möglich zu erledigen
und die verfügbare CPU-Kapazität auf alle Threads gleichmäßig zu verteilen.Wenn Du einen Hintergrund-Thead startest, wird das Ganze deswegen nicht langsamer (heizen)
sondern der Thread bekommt nur dann weniger Rechenzeit zugeteilt, wenn andere Aufgaben anstehen.Sinnvoller im Hinblick auf die Lebenszeit des Laptops - und auf das Vermeiden von Brandblasen:
Reduziere wenn möglich den CPU Takt im BIOS, wenn die CPU älteren Datums ist und keine
der neueren CPU-Throttling Mechanismen unterstützt.
Bei Windows in neueren Versionen (Vista/7) kann man über die Systemsteuerung Energieoptionen (erweitert)
die Prozessorleistung reduzieren - was jedoch nur in Verbindung mit entsprechenden Treibern richtig funktioniert.
Dann wird das Ganze etwas langsamer laufen, der Rechner kann aber deutlich länger leben.
Zudem solltest Du andere Hintergrundprogramme stoppen (auch Virenscanner heizen manchmal
ganz schön ein ;-)Um die Arbeit in einem Hintergrundthread anzuhalten, kannst Du dies über ein ManualResetEvent
steuern. Üblicherweise verwendet man das, um noch nicht fertige Aufgaben zu warten.
Es kann aber auch andersherum eingesetzt werden.Gruß Elmar
- Als Antwort markiert '_OMEGA_' Montag, 30. Mai 2011 04:12
Alle Antworten
-
Die einfachste Lösung ist, die Schleife in einem Hintergrund-Thread mit niedriger Priorität laufen zu lassen. In diesem Fall kann auf DoEvents verzichtet werden und auch mit einem Thread.Sleep die Abarbeitung der Schleife zeitweilig unterbrochen werden. Zu beachten sind ledig thread-übergreifende Zugriffe auf nicht threadsichere Objekte, wie beispielsweise Steuerelemente in der Oberfläche. Aber auch diese Probleme können einfach umgangen werden, wenn ein BackgroundWorker genutzt wird.--
Viele Grüße
Peter -
Vielen Dank für die Antwort.
Ich habe das soweit umgesetzt, das Prog. reagiert auch gut, und die PC-Performance ist auch noch gut - aber der CPU-Kern kommt dennoch an seine Genzen.
Im Start button habe ich jetzt:
thread_array.IsBackground = True thread_array.Start()
und am Ende der Schleife:
thread_array.Abort()
Gibt es eine Methode, mit der man den Thread oder die Schleife anhalten kann, um die CPU etwas abkühlen zu lassen?
@Peter Fleischer: War ne gute Antwort, obwohl es nicht ganz das war, was ich gesucht habe.
Hat ne andere Frage beantwortet :)
'_OMEGA_'
-
warum darf deine CPU nicht mit 100% arbeiten?
Wenn deine CPU heiß wird, dann liegt das halt in der Natur der Sache und sollte bei korrekter Kühlung auch keine Probleme machen.
Wenn der Thread im Hintergrund mit niedrigerer Prio läuft, stört das ja nichtmal andere Programme (wenn sie Rechenleistung benötigen, wird dein Thread einfach weggedrückt) - und man hat in der Regel sogar mehrere Kerne zur Verfügung.
Wenn du unbedingt den Kern etwas "entlasten" willst, wird dir wohl nur ein Sleep was helfen. Der Suspended den Thread einfach und du kannst recht leicht durch die Zeit den Abkühlungsvorgang steuern... Möglich wäre leicht auch die Abfrage der Temperatur (über WMI in nem 2. Thread). Du kannst natürlich auch den Thread Suspenden und resumen - aber das musste auch von "ausserhalb" des Workerthreads machen, was es auch nicht leichter machen würde.
Viel Spass
-
"warum darf deine CPU nicht mit 100% arbeiten?" - Weil mein laptop (habe zur zeit leider nichts anderes zur verfügung) sehr schnell heiß wird und den ProductKey unten drunter schon halb durchgeschmoort hat.
.suspend ist laut VS 2010 'veraltet' und man wird gebeten etwas anderes zu nutzen.
Zu thread.sleep(n):
http://social.msdn.microsoft.com/Forums/de/visualbasicde/thread/65420920-4242-4ce7-977e-90ff5def730b
bzw.
Wahrscheinlich lasse ich das einfach so, wie es ist. Läuft ja.
-
Also is sehe keinen Grund Sleep nicht zu nutzen. Es ist in deinem Fall vermutlich der einfachste und eleganteste Weg. Und der Artikel (hab nur den zweiten gelesen) beschreibt eher Scenarios wo Programmlogik auf Sleeps beruht - und das macht man dann vielleicht eher mit Timern. .
Du willst ja nur die CPU zyklisch abkühlen lassen... Wenn du das alle 2 Sekunden für 2 Sekunden machst, sollte das die CPU entlasten - allerdings deine Berechnung entsprechend länger dauern lassen ^^. Ich würde längere Abkühlphasen allerdings vermeiden, da die Hardware sonst durch das ständige auf und abkühlen auch nicht besser wird... Auf wieviel % CPU Auslastung du hier kommen kannst, ohne zu "+berhitzen" kannste jaausprobieren.
-
Hallo,
wenn Dein Laptop schlecht gekühlt wird, so lässt sich das durch Dein Programm bedingt beeinflussen.
Auf Programmseite kannst Du am ehesten Einfluss darauf nehmen, in dem Du den Algorithmus optimierst.Das Betriebssystem ist darauf ausgelegt, alle anfallende Arbeit so schnell wie möglich zu erledigen
und die verfügbare CPU-Kapazität auf alle Threads gleichmäßig zu verteilen.Wenn Du einen Hintergrund-Thead startest, wird das Ganze deswegen nicht langsamer (heizen)
sondern der Thread bekommt nur dann weniger Rechenzeit zugeteilt, wenn andere Aufgaben anstehen.Sinnvoller im Hinblick auf die Lebenszeit des Laptops - und auf das Vermeiden von Brandblasen:
Reduziere wenn möglich den CPU Takt im BIOS, wenn die CPU älteren Datums ist und keine
der neueren CPU-Throttling Mechanismen unterstützt.
Bei Windows in neueren Versionen (Vista/7) kann man über die Systemsteuerung Energieoptionen (erweitert)
die Prozessorleistung reduzieren - was jedoch nur in Verbindung mit entsprechenden Treibern richtig funktioniert.
Dann wird das Ganze etwas langsamer laufen, der Rechner kann aber deutlich länger leben.
Zudem solltest Du andere Hintergrundprogramme stoppen (auch Virenscanner heizen manchmal
ganz schön ein ;-)Um die Arbeit in einem Hintergrundthread anzuhalten, kannst Du dies über ein ManualResetEvent
steuern. Üblicherweise verwendet man das, um noch nicht fertige Aufgaben zu warten.
Es kann aber auch andersherum eingesetzt werden.Gruß Elmar
- Als Antwort markiert '_OMEGA_' Montag, 30. Mai 2011 04:12
-
MRE klingt gut.
Habe damit vorher noch nie gearbeitet, und weiß jetzt nicht genau wie ich das machen soll.
ich habe einen timer, der beim starten aktiviert wird.
im timer.tick event steht folgendes
Private Sub Timer_DoEvents_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer_DoEvents.Tick If _pause = True Then mre.WaitOne() btn_Pause.BackColor = Color.Red _pause = False ElseIf _pause = False Then mre.Set() 'edit: habe ich auf Reset() geändert, dadurch friert aber die anwendung ein. btn_Pause.BackColor = Color.Green _pause = True End If End Sub
Edit: wenn ich das jetzt richtig verstanden habe, dann wird durch mre.Reset() der aktuelle thread geblockt. wie kann ich das auf einen anderen thread beziehen?
intervall ist auf 1s gesetzt.
von daher blinkt der button fröhlich vor sich hin, aber der thread wird nicht angehalten.
muss ich MRE noch irgendwie sagen welcher thread das ist? weil ich den timer nicht in dem thread habe?
Dim thread_array As New Threading.Thread(AddressOf array_v3) Private Shared mre As New ManualResetEvent(False)
habe ich ganz oben in den deklarierungen.
die schleife wird in "Public Sub array_v3()" ausgeführt.
-
Hallo,
Das Wait müsste hier im Arbeitsthread stattfinden,
und Dein Steuerteil durch Set/Reset das Blockieren steuern.Wobei es periodisch durch einen Timer anzuhalten ist letztendlich verquer.
Wie heute morgen schon geschrieben: Versuche Deinen Rechner so einzurichten
dass er auch unter Last funktioniert - denn jedes Überschreitern der TDP
beschleunigt das Ableben exponential.
Solltest Du mal Tuning-Maßnahmen vorgenommen haben, wie sie so gerne
in den Tipps und Tricks-Ecken verbreitet werden, nimm sie zurück.Ich habe mal ein Beispiel in Verbindung mit einem BackgroundWorker zusammengestellt:
Imports System.ComponentModel Imports System.Threading Public Class PauseWorkerForm Dim WithEvents worker As BackgroundWorker Dim workerPause As Boolean Dim workerPauseEvent As ManualResetEvent Public Sub New() ' 3 Buttons: startButton, pauseButton, stopButton ' 1 Label: progressLabel InitializeComponent() worker = New BackgroundWorker() worker.WorkerReportsProgress = True worker.WorkerSupportsCancellation = True AddHandler worker.DoWork, AddressOf Worker_DoWork AddHandler worker.ProgressChanged, AddressOf Worker_ProgressChanged AddHandler worker.RunWorkerCompleted, AddressOf Worker_RunWorkerCompleted workerPause = False workerPauseEvent = New ManualResetEvent(True) Me.pauseButton.Enabled = False Me.stopButton.Enabled = False End Sub #Region "Start, Pausieren, Stoppen" Private Sub StartWorker() workerPause = False workerPauseEvent.Set() ' Durchlässig worker.RunWorkerAsync() End Sub Private Sub PauseWorker() If worker.IsBusy Then If workerPause Then workerPause = False Me.workerPauseEvent.Set() ' freigeben Else workerPause = True Me.workerPauseEvent.Reset() ' blockieren End If End If End Sub Private Sub StopWorker() ' Beendet die Arbeit If worker.IsBusy Then ' Blockierung aufheben, wenn pausiert, damit CancellationPending geprüft wird If workerPause Then workerPause = False Me.workerPauseEvent.Set() End If ' Abbrechen worker.CancelAsync() End If End Sub #End Region #Region "Button Ereignisse" Private Sub startButton_Click(sender As Object, e As System.EventArgs) _ Handles startButton.Click Me.startButton.Enabled = False Me.pauseButton.Enabled = True Me.pauseButton.Text = "Pause" Me.stopButton.Enabled = True StartWorker() End Sub Private Sub pauseButton_Click(sender As Object, e As System.EventArgs) _ Handles pauseButton.Click PauseWorker() If (workerPause) Then Me.pauseButton.Text = "Weiter" Else Me.pauseButton.Text = "Pause" End If End Sub Private Sub stopButton_Click(sender As Object, e As System.EventArgs) _ Handles stopButton.Click StopWorker() End Sub Private Sub PauseWorkerForm_FormClosing(sender As Object, e As FormClosingEventArgs) _ Handles MyBase.FormClosing ' Formular schliessen, Worker Stoppen StopWorker() End Sub #End Region #Region "Backgroundworker Ereignisse" Private Sub Worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) ' Arbeitschleife, hier via Random simuliert Const LoopCount As Integer = 1000000 Dim r As New Random() Console.WriteLine("Worker gestartet") For index As Integer = 0 To LoopCount ' Wird blockiert, wenn ManualResetEvent False (Reset) ist. workerPauseEvent.WaitOne() ' Abbruch durch stopButton (oder Schliessen des Formulars) If worker.CancellationPending Then Console.WriteLine("Worker abgebrochen") e.Result = "Abgebrochen" Return End If ' ... Hier käme richtige Arbeit hin ... Dim value = r.Next(Integer.MaxValue) 'Thread.Sleep(100) ' Fortschrittsanzeige If index Mod 1000 = 0 Then Dim progressPercent = index * 100 \ LoopCount worker.ReportProgress(progressPercent, value) End If Next e.Result = "Fertig" Console.WriteLine("Worker beendet") End Sub Private Sub Worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) ' Benachrichtigung Dim value = CInt(e.UserState) Me.progressLabel.Text = String.Format("{0} % Ausgabe: {1}", e.ProgressPercentage, value) Me.progressLabel.Refresh() End Sub Private Sub Worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) ' Beendet entweder Arbeit fertig oder Abbgebrochen (e.Cancelled) ' Endergebnis (hier eine Zeichenkette) Console.WriteLine("Ergebnis " & CStr(e.Result)) ' Für nächsten Durchlauf bereit pauseButton.Enabled = False pauseButton.Text = "Pause" stopButton.Enabled = False startButton.Enabled = True End Sub #End Region End Class
Dort wo ich sinnfrei neue Zahlen erzeuge, käme Deine Arbeitsschleife hin.
Gruß Elmar
-
Danke, ich habe es endlich geschafft.
Ich habe es nicht mit einem BackgroundWorker gemacht, sondern mit einem boolean-switch im timer und den mre.set(), mre.reset() und waitone() anweisungen geschafft.
mre.set() und mre.reset sind im timer.tick event.
mre.waitone() ist in der arbeitsschleife.
für weitere informationen, schreibt mich mich an.
bitte entschuldigt die schreibweise, ich bin inner schule und hab nicht viel zeit.
'_OMEGA_'