Wenn jemand viel Erfahrung mit Timing-Code hatte, der auf dem VCL-Hauptthread läuft, würde ich gerne eine Meinung dazu bekommen. Ich habe etwas Code, der in meiner Delphi 6-Anwendung auf dem Hauptthread einige schwere String-Verarbeitung ausführt. Jedes Mal, wenn ich eine Operation starte, schwebt die Zeit für jede Operation um 50 ms an einem einzelnen Thread auf meinem i5 Quad Core. Was mich wirklich misstrauisch macht ist, dass der selbe Code, der auf einem alten Pentium 4 läuft, dieselbe Zeit für die Operation anzeigt, wenn ich normalerweise sehe, dass Code auf dem Pentium 4 etwa 4 mal langsamer läuft als der Quad Core. Ich beginne mich zu fragen, ob der Code wesentlich weniger Zeit als 50 ms verbrauchen würde, aber dass etwas an dem Haupt-VCL-Thread, vielleicht Windows-Nachrichtenbehandlung oder Windows API-Aufrufe, ein künstliches "Floor" für den Vorgang erzeugt. Beachten Sie, dass eine Operation durch eine eingehende Anfrage an einem Socket ausgelöst wird, wenn dies von Bedeutung ist, die Zeitmessung jedoch erst stattfindet, wenn die Daten vollständig empfangen wurden.
Bevor ich den gesamten Code zum Testen auf einen Hintergrund-Thread verschiebe, frage ich mich, ob jemand in diesem Bereich allgemeines Wissen hat? Was waren Ihre Erfahrungen mit Code, der auf dem Haupt-VCL-Thread ausgeführt wird? Beachten Sie, dass die Timing-Messungen durchgeführt werden, wenn während der Tests absolut keine vom Benutzer ausgelöste Aktivität stattfindet.
Ich frage mich auch, ob es etwas bringen würde, die Priorität des Threads auf knapp unter Echtzeit zu erhöhen. Ich habe noch nie eine Verbesserung meiner Laufzeiten beim Experimentieren mit diesen Flags gesehen.
- roschler
Ohne einfachen Quellcode, um das Problem zu reproduzieren und wie Sie Ihre Threads zeitlich festlegen, ist es schwierig zu verstehen, was in Ihrer Software vorkommt.
Klingt definitiv wie:
Über den letzten Punkt, bedenken Sie dies:
LOCK DEC/INC
, die auf Multi-Code-CPU nicht so gut skaliert thread char-level process, wobei zB PChar
für statische Puffer anstelle von string
) verwendet wird. Ich bin sicher, dass Sie ohne string
-Operationen feststellen werden, dass alle Threads äquivalent sind.
Kurz gesagt: weder die aktuelle Delphi MM, noch die aktuelle String-Implementierung skaliert gut auf Multicore-CPU. Sie haben gerade ein bekanntes Problem der aktuellen RTL herausgefunden. Lesen Sie diese SO-Frage .
Wenn alle Threads die gleiche Priorität haben, wie sie es normalerweise tun, kann es aus folgenden Gründen keinen Unterschied geben. Wenn Sie einen Unterschied feststellen, überprüfen Sie den Code erneut (stellen Sie sicher, dass Sie dasselbe in VCL- und Hintergrundthreads ausführen), und stellen Sie sicher, dass Sie die Zeit richtig einstellen:
Der Compiler generiert genau den gleichen Code, es ist egal, ob der Code im Hauptthread oder in einem Hintergrundthread ausgeführt wird. Tatsächlich können Sie den gesamten Code in eine Prozedur einfügen und diese sowohl vom Execute()
des Worker-Threads als auch vom VCL-Hauptthread aufrufen.
Für die CPU sind alle Kerne und alle Threads gleich. Es sei denn, es handelt sich tatsächlich um eine Hyperthreading-CPU, bei der nicht alle Kerne real sind, aber dann die nächste Kugel.
Auch wenn nicht alle CPU - Kerne gleich sind, wird Ihr Thread sehr unwahrscheinlich auf demselben Kern laufen , das Betriebssystem kann sie beliebig verschieben (und plant tatsächlich Ihren Thread zu verschiedenen Zeiten auf verschiedenen Kernen laufen).
Der Messaging-Overhead ist für den VCL-Hauptthread nicht von Bedeutung, denn wenn Sie Application.ProcessMessages()
nicht manuell aufrufen, wird der Message-Pump einfach gestoppt, während Ihre Prozedur funktioniert. Die Nachrichtenpumpe ist passiv, Ihr Thread muss Nachrichten von der Warteschlange anfordern, aber da der Thread beschäftigt ist, Ihre Arbeit zu erledigen, fordert er keine Nachrichten an, also keinen Overhead.
Es gibt nur eine Stelle, an der Threads nicht gleich sind, und dies kann die wahrgenommene Ausführungsgeschwindigkeit ändern: Es ist das Betriebssystem, das Threads für Ausführungseinheiten (Kerne) plant und für die Betriebssystem-Threads unterschiedliche Prioritäten hat. Sie können dem Betriebssystem mitteilen, dass ein bestimmter Thread mithilfe des % anders behandelt werden muss. co_de% API (die von der SetThreadPriority()
-Eigenschaft verwendet wird).
Ohne einfachen Quellcode, um das Problem zu reproduzieren und wie Sie Ihre Threads zeitlich festlegen, ist es schwierig zu verstehen, was in Ihrer Software vorkommt.
Klingt definitiv wie:
Über den letzten Punkt, bedenken Sie dies:
Ich bin sicher, dass Sie ohne %code% -Operationen feststellen werden, dass alle Threads äquivalent sind.
Kurz gesagt: weder die aktuelle Delphi MM, noch die aktuelle String-Implementierung skaliert gut auf Multicore-CPU. Sie haben gerade ein bekanntes Problem der aktuellen RTL herausgefunden. Lesen Sie diese SO-Frage .
Wenn alle Threads die gleiche Priorität haben, wie sie es normalerweise tun, kann es aus folgenden Gründen keinen Unterschied geben. Wenn Sie einen Unterschied feststellen, überprüfen Sie den Code erneut (stellen Sie sicher, dass Sie dasselbe in VCL- und Hintergrundthreads ausführen), und stellen Sie sicher, dass Sie die Zeit richtig einstellen:
Der Compiler generiert genau den gleichen Code, es ist egal, ob der Code im Hauptthread oder in einem Hintergrundthread ausgeführt wird. Tatsächlich können Sie den gesamten Code in eine Prozedur einfügen und diese sowohl vom %code% des Worker-Threads als auch vom VCL-Hauptthread aufrufen.
Für die CPU sind alle Kerne und alle Threads gleich. Es sei denn, es handelt sich tatsächlich um eine Hyperthreading-CPU, bei der nicht alle Kerne real sind, aber dann die nächste Kugel.
Auch wenn nicht alle CPU - Kerne gleich sind, wird Ihr Thread sehr unwahrscheinlich auf demselben Kern laufen , das Betriebssystem kann sie beliebig verschieben (und plant tatsächlich Ihren Thread zu verschiedenen Zeiten auf verschiedenen Kernen laufen).
Der Messaging-Overhead ist für den VCL-Hauptthread nicht von Bedeutung, denn wenn Sie %code% nicht manuell aufrufen, wird der Message-Pump einfach gestoppt, während Ihre Prozedur funktioniert. Die Nachrichtenpumpe ist passiv, Ihr Thread muss Nachrichten von der Warteschlange anfordern, aber da der Thread beschäftigt ist, Ihre Arbeit zu erledigen, fordert er keine Nachrichten an, also keinen Overhead.
Es gibt nur eine Stelle, an der Threads nicht gleich sind, und dies kann die wahrgenommene Ausführungsgeschwindigkeit ändern: Es ist das Betriebssystem, das Threads für Ausführungseinheiten (Kerne) plant und für die Betriebssystem-Threads unterschiedliche Prioritäten hat. Sie können dem Betriebssystem mitteilen, dass ein bestimmter Thread mithilfe des % anders behandelt werden muss. co_de% API (die von der %code% -Eigenschaft verwendet wird).
Fragen Sie, ob ein Hintergrund-Thread schneller wäre? Wenn Ihr Hintergrundthread den gleichen Code wie der Hauptthread ausführen würde und nichts anderes im Hauptthread stattfindet, können Sie nichts mit einem Hintergrundthread gewinnen. Threads sollten verwendet werden, um Verarbeitungslasten zu teilen und zu verteilen, die andernfalls miteinander konkurrieren und / oder sich gegenseitig blockieren würden, wenn sie im Hauptthread ausgeführt werden. Da Sie mit einem Fall zu tun haben, in dem Ihr Hauptthread ansonsten inaktiv ist, hilft das einfache Erstellen eines Threads zum Ausführen von langsamem Code nicht.
Threads sind keine Zauberei, sie können keinen langsamen Code beschleunigen oder Verarbeitungsengpässe in einem bestimmten Segment eliminieren, die nicht im Zusammenhang mit Konflikten im Hauptthread stehen. Stellen Sie sicher, dass Ihr Code nicht etwas tut, von dem Sie nichts wissen und dass Ihre Timing-Methode korrekt ist.
Meine erste
Die Leistung kann nicht statisch bewertet werden. Dazu müssen Sie AQTime oder einen anderen Leistungsprofiler für Delphi abrufen. Ich benutze AQtime, und ich liebe es, aber ich bin mir bewusst, dass es teuer ist.
Ihr Code wird nicht magisch schneller, nur weil Sie ihn in einen Hintergrund-Thread verschoben haben. Die All-inclusive-Zeit, bis Sie Ergebnisse in Ihrer Benutzeroberfläche sehen, kann etwas langsamer werden, wenn Sie viele Daten aus dem Hintergrundthread mithilfe einiger Synchronisierungsmechanismen an den Vordergrundthread senden müssen.
Wenn Sie jedoch Teile Ihres Algorithmus parallel ausführen könnten, das heißt, Ihre Arbeit teilen, so dass Sie zwei oder mehr Worker-Threads haben, die Ihre Daten verarbeiten, und Sie einen Quad-Core-Prozessor haben, dann ist Ihre Gesamtzeit ein fester Vorgang Belastung der Arbeit, könnte abnehmen. Das bedeutet nicht, dass der Code schneller ausgeführt werden würde, aber abhängig von vielen Faktoren können Sie einen leichten Vorteil von Multithreading bis zur Anzahl der Kerne in Ihrem Computer erzielen. Es wird niemals ein 2x Performance-Boost sein, zwei Threads anstelle von einem zu verwenden, aber in Ihren mehr als ein Threads umfassenden parallelen Lösungen können Sie eine um 20-40% bessere Performance erzielen, je nachdem, wie skalierbar Ihr Heap ist unter Multithreading-Lasten und wie IO / Speicher / Cache Ihre Arbeitslast gebunden ist.
Was das Erhöhen der Threadprioritäten anbelangt, so wird im Allgemeinen alles, was Sie dort tun, das empfindliche Gleichgewicht der Leistung Ihres Windows-Systems stören. Durch die Erhöhung der Prioritäten erreichen Sie (manchmal) eine nominale, aber nicht wiederholbare und nicht garantierbare Leistungssteigerung. Abhängig von den anderen Dingen, die Sie in Ihrem Code und Ihren Datenquellen tun, kann das Spielen mit Prioritäten von Threads zu subtilen Problemen führen. Weitere Informationen finden Sie unter Restaurants Philosophen .
Die beste Möglichkeit, die Geschwindigkeit von String-Operationen zu optimieren, besteht darin, sie zuerst zu testen und genau herauszufinden, wo sie die meiste Zeit verwendet. Ist es Heap-Operationen? Speicher Kopieren und Verschieben von Vorgängen? Ohne einen Profiler, selbst mit Ratschlägen anderer Leute, werden Sie immer noch eine Kardinalsünde des Programmierens begehen; vorzeitige Optimierung. Ergebnisorientiert sein. Sei wissenschaftlich orientiert. Messen. Verstehen. Entscheide dich dann.
Nachdem ich das gesagt habe, habe ich eine Menge schrecklichen Code in meiner Zeit gesehen, und es gibt eine tolle Sache, die Leute machen, die ihre Thread-App-Performance total umbringt; Verwenden Sie TThread.Synchronize zu viel.
Hier ist ein pathologischer (Extrem-) Fall, der leider ziemlich häufig in freier Wildbahn vorkommt:
%Vor%Das Problem hierbei ist, dass 100% der Arbeit wirklich im Vordergrund ausgeführt wird, abgesehen von der Prüfung "wenn beendet", die im Thread-Kontext ausgeführt wird. Um den obigen Code noch schlimmer zu machen, fügen Sie einen nicht unterbrechbaren Schlaf hinzu.
Verwenden Sie für schnellen Hintergrund-Thread-Code nur sehr sparsam oder gar nicht und stellen Sie sicher, dass der aufgerufene Code einfach ist und schnell ausgeführt wird, oder besser noch TThread.Queue oder PostMessage, wenn Sie wirklich mit der Haupt-Thread-Aktivität leben könnten .
Wenn jemand viel Erfahrung mit Timing-Code hatte, der auf dem VCL-Hauptthread läuft, würde ich gerne eine Meinung dazu bekommen. Ich habe etwas Code, der in meiner Delphi 6-Anwendung auf dem Hauptthread einige schwere String-Verarbeitung ausführt. Jedes Mal, wenn ich eine Operation starte, schwebt die Zeit für jede Operation um 50 ms an einem einzelnen Thread auf meinem i5 Quad Core. Was mich wirklich misstrauisch macht ist, dass der selbe Code, der auf einem alten Pentium 4 läuft, dieselbe Zeit für die Operation anzeigt, wenn ich normalerweise sehe, dass Code auf dem Pentium 4 etwa 4 mal langsamer läuft als der Quad Core. Ich beginne mich zu fragen, ob der Code wesentlich weniger Zeit als 50 ms verbrauchen würde, aber dass etwas an dem Haupt-VCL-Thread, vielleicht Windows-Nachrichtenbehandlung oder Windows API-Aufrufe, ein künstliches "Floor" für den Vorgang erzeugt. Beachten Sie, dass eine Operation durch eine eingehende Anfrage an einem Socket ausgelöst wird, wenn dies von Bedeutung ist, die Zeitmessung jedoch erst stattfindet, wenn die Daten vollständig empfangen wurden.
Bevor ich den gesamten Code zum Testen auf einen Hintergrund-Thread verschiebe, frage ich mich, ob jemand in diesem Bereich allgemeines Wissen hat? Was waren Ihre Erfahrungen mit Code, der auf dem Haupt-VCL-Thread ausgeführt wird? Beachten Sie, dass die Timing-Messungen durchgeführt werden, wenn während der Tests absolut keine vom Benutzer ausgelöste Aktivität stattfindet.
Ich frage mich auch, ob es etwas bringen würde, die Priorität des Threads auf knapp unter Echtzeit zu erhöhen. Ich habe noch nie eine Verbesserung meiner Laufzeiten beim Experimentieren mit diesen Flags gesehen.
- roschler
Die Leistung kann nicht statisch bewertet werden. Dazu müssen Sie AQTime oder einen anderen Leistungsprofiler für Delphi abrufen. Ich benutze AQtime, und ich liebe es, aber ich bin mir bewusst, dass es teuer ist.
Ihr Code wird nicht magisch schneller, nur weil Sie ihn in einen Hintergrund-Thread verschoben haben. Die All-inclusive-Zeit, bis Sie Ergebnisse in Ihrer Benutzeroberfläche sehen, kann etwas langsamer werden, wenn Sie viele Daten aus dem Hintergrundthread mithilfe einiger Synchronisierungsmechanismen an den Vordergrundthread senden müssen.
Wenn Sie jedoch Teile Ihres Algorithmus parallel ausführen könnten, das heißt, Ihre Arbeit teilen, so dass Sie zwei oder mehr Worker-Threads haben, die Ihre Daten verarbeiten, und Sie einen Quad-Core-Prozessor haben, dann ist Ihre Gesamtzeit ein fester Vorgang Belastung der Arbeit, könnte abnehmen. Das bedeutet nicht, dass der Code schneller ausgeführt werden würde, aber abhängig von vielen Faktoren können Sie einen leichten Vorteil von Multithreading bis zur Anzahl der Kerne in Ihrem Computer erzielen. Es wird niemals ein 2x Performance-Boost sein, zwei Threads anstelle von einem zu verwenden, aber in Ihren mehr als ein Threads umfassenden parallelen Lösungen können Sie eine um 20-40% bessere Performance erzielen, je nachdem, wie skalierbar Ihr Heap ist unter Multithreading-Lasten und wie IO / Speicher / Cache Ihre Arbeitslast gebunden ist.
Was das Erhöhen der Threadprioritäten anbelangt, so wird im Allgemeinen alles, was Sie dort tun, das empfindliche Gleichgewicht der Leistung Ihres Windows-Systems stören. Durch die Erhöhung der Prioritäten erreichen Sie (manchmal) eine nominale, aber nicht wiederholbare und nicht garantierbare Leistungssteigerung. Abhängig von den anderen Dingen, die Sie in Ihrem Code und Ihren Datenquellen tun, kann das Spielen mit Prioritäten von Threads zu subtilen Problemen führen. Weitere Informationen finden Sie unter Restaurants Philosophen .
Die beste Möglichkeit, die Geschwindigkeit von String-Operationen zu optimieren, besteht darin, sie zuerst zu testen und genau herauszufinden, wo sie die meiste Zeit verwendet. Ist es Heap-Operationen? Speicher Kopieren und Verschieben von Vorgängen? Ohne einen Profiler, selbst mit Ratschlägen anderer Leute, werden Sie immer noch eine Kardinalsünde des Programmierens begehen; vorzeitige Optimierung. Ergebnisorientiert sein. Sei wissenschaftlich orientiert. Messen. Verstehen. Entscheide dich dann.
Nachdem ich das gesagt habe, habe ich eine Menge schrecklichen Code in meiner Zeit gesehen, und es gibt eine tolle Sache, die Leute machen, die ihre Thread-App-Performance total umbringt; Verwenden Sie TThread.Synchronize zu viel.
Hier ist ein pathologischer (Extrem-) Fall, der leider ziemlich häufig in freier Wildbahn vorkommt:
%Vor%Das Problem hierbei ist, dass 100% der Arbeit wirklich im Vordergrund ausgeführt wird, abgesehen von der Prüfung "wenn beendet", die im Thread-Kontext ausgeführt wird. Um den obigen Code noch schlimmer zu machen, fügen Sie einen nicht unterbrechbaren Schlaf hinzu.
Verwenden Sie für schnellen Hintergrund-Thread-Code nur sehr sparsam oder gar nicht und stellen Sie sicher, dass der aufgerufene Code einfach ist und schnell ausgeführt wird, oder besser noch TThread.Queue oder PostMessage, wenn Sie wirklich mit der Haupt-Thread-Aktivität leben könnten .
Fragen Sie, ob ein Hintergrund-Thread schneller wäre? Wenn Ihr Hintergrundthread den gleichen Code wie der Hauptthread ausführen würde und nichts anderes im Hauptthread stattfindet, können Sie nichts mit einem Hintergrundthread gewinnen. Threads sollten verwendet werden, um Verarbeitungslasten zu teilen und zu verteilen, die andernfalls miteinander konkurrieren und / oder sich gegenseitig blockieren würden, wenn sie im Hauptthread ausgeführt werden. Da Sie mit einem Fall zu tun haben, in dem Ihr Hauptthread ansonsten inaktiv ist, hilft das einfache Erstellen eines Threads zum Ausführen von langsamem Code nicht.
Threads sind keine Zauberei, sie können keinen langsamen Code beschleunigen oder Verarbeitungsengpässe in einem bestimmten Segment eliminieren, die nicht im Zusammenhang mit Konflikten im Hauptthread stehen. Stellen Sie sicher, dass Ihr Code nicht etwas tut, von dem Sie nichts wissen und dass Ihre Timing-Methode korrekt ist.
Meine erste
Tags und Links multithreading delphi performance timing vcl