Autor Beitrag
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 376
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Sa 20.06.15 23:16 
Hallo,

in der Rechenaufgabe 3*5+7*11 könnt man ja die Aufgabe 3*5 und 7*11 getrennten Threads übergeben, die würden dann auf einem Multicore-Prozessor parallel ausgeführt. Der Hauptthread wartet auf die beiden Unter-Threads und führt dann die Addition aus. Das wäre die schnellste Möglichkeit für die Berechnung - wenn nicht die Threadverwaltung wäre!!!!!

Meine Frage also: Hat jemand einen Richtwert, eine Faustformel oder so, ab welcher "Größe" zweier Teilaufgaben (3*5 und 7*11 im Beispiel) eine Aufteilung auf Threads zu einem Geschwindigkeitsgewinn führt?

(Für Google fehlten mir irgendwie die Suchworte.) Falls niemand antwortet, mache ich vermutlich Ende der Woche mal systematische Versuche und poste die Ergebnisse hier.

Viele Grüße
GuaAck
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 21.06.15 07:43 
Ein wenig mehr muss es schon sein, damit die Threads einen Geschwindigkeitsvorteil bringen, das weißt du ja wohl schon.

Grob geschätzt wird es in den meisten Fällen nicht viel bringen weniger als 200 Millisekunden Ausführungszeit in einen eigenen Thread zu packen. (Aber der Wert ist natürlich vom Prozessor und von den Aufgaben abhängig, die der Thread ausführt. Das ist kein empirischer Wert, sondern eine Schätzung von mir.)
Anders sieht es aus, wenn der Thread die ganze Zeit läuft und viele einzelne kleine Aufgaben einfach der Reihe nach abarbeitet, da machen ggf. auch kleinere Aufgaben Sinn.

Geht es um einen konkreten Fall? Da ließe sich eher etwas Konkretes sagen.
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 376
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Di 23.06.15 23:33 
Hallo,

falls es interessiert (und Jaenicke interessiert es bestimmt), ich habe mal ein paar Versuche gemacht. Vorab: Bei einer 4 GHz-CPU lohnt es, parallel zu lösende Teilaufgaben, die je 30 Mikrosekunden oder länger dauern, in Threads unterzubringen, damit sie von mehreren Kernen der CPU parallel verarbeitet werden können.

Zu meinem Test (Zwei primitive Zufallszahlen-Generatoren):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
     FOR i := 1 TO anz_schleifena DO
        BEGIN
          FOR j := 1 TO anz_schleifeni DO
            Seed1 := (a * Seed1 + C) MOD m;
          FOR j := 1 TO anz_schleifeni DO
            Seed2 := (a * Seed2 + C) MOD m;
          summe := (summe + Seed1 + Seed2) MOD m;
        END;


Ich habe immer gesetzt "anz_schleifeni*anz_schleifena=10^8", somit ist die Rechenarbeit immer fast gleich. Rechenzeit ohne Aufteilung auf Threads ist tatsächlich immer gleich. Die Summenbildung fällt nicht ins Gewicht.

Die beiden inneren Schleifen kann man offensichtlich parallel bearbeiten. Dafür habe ich zum Vergleich zwei Threads erzeugt, die genau die innere Schleife enthalten. Die Threads starte ich per Event, warte auf die Fertigmeldung über eine Zähl-Semaphore und bilde dann die Summe.


Bei anz_schleifeni > 10000 ergibt sich damit etwa die halbe Rechenzeit gegenüber dem dargestellten Code.

Bei anz_schleifeni = 1000 wird etwa 70 % der Rechenzeit des dargestelten Codes gebraucht, bei 100 schon mehr als das Doppelte!

Ohne Threads braucht mein Rechner für 10^8 Durchläufe 6,3 s, die einmalige Berechnung eines Seedx (incl. FOR..) also so etwa 30 ns; in einer Schleife bis 1000 sind das also die 30 us.

Wer will, mein Testprogramm als ZIP im Anhang.

Viele Grüße
GuaAck
Einloggen, um Attachments anzusehen!
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1652
Erhaltene Danke: 243

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Do 25.06.15 09:55 
Hallo,

die Daten von user profile iconGuaAck passen bei mir mit Win7.
Egal, ob Turbo-Delphi ( kein SpinEdit :-( ) oder Lazarus 1.4 ( uses windows, ).
Nur ist der 3.5 Ghz i4330 etwas schneller.Nur Hauptthread in 5.3 s.Die Haswell-CPU dividiert halt gern ;-)

Gruß Horst
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Do 25.06.15 16:52 
Und dann ist da noch eine harte Grenze: wenn du nicht wenigstens eine Timeslice voll machst, hast du definitiv mehr Overhead, denn früher kann dein Event einfach nicht zurückkommen.

Wie lang so eine Timeslice nun ist, ist unter Windows allerdings nicht konstant. Es waren mal 20ms, mit schnelleren CPUs hat sich das aber geändert und mittlerweile kann das je nach HAL irgendwas aus 3ms, 5ms oder 180ms sein. Oder auch 10ms oder 15ms, wenn die Performance-Optionen auf "Vordergrundanwendungen" stehen.

Wenn du kontinuierlich Daten verarbeiten willst, macht es deswegen durchaus Sinn so zu zielen, dass du knapp vor Ende einer Timeslice fertig bist und keine Zeit in Waitlocks verheizt.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 25.06.15 17:56 
CPU: i7-3610QM, 2.3GHz
Hauptthread --- 2 Threads
64Bit
87822
3,27 ------------ 1,66
-
32Bit
87822
9,58 ------------ 4,91
-------------------------------------------
Zitat:
The term "quantum" is a unitless measure of time for each time slice that a thread will run until a "context switch" occurs and another thread (either within the same program or from within another program) is selected to run. This prevents a CPU-bound process from monopolizing the processor. Currently in Windows, 3 quantums are equal to either 10 milliseconds (single processor) or 15 milliseconds (multiple-processor Pentium). This depends on the hardware abstraction layer (HAL) selected for your computer. Original Equipment Manufacturer (OEM) HALs may have a different value. Time slices that are fixed at 36 quantums are currently used when background services are selected (as you might choose in a typical server installation).

The situation become more complex when you enable the Foreground Applications option. This introduces the "variable quantum" concept. In this case, background tasks receive a different quantum than the quantums received by the foreground tasks. Also, both sets of quantums are shorter than a thread would receive on a computer set for background services. Currently, a background process receives a quantum of 3 and a foreground process receives a quantum of 9. Therefore, you can calculate the length of time the thread will run before its timer expires.

support.microsoft.co...259025?wa=wsignin1.0
jfheins
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 918
Erhaltene Danke: 158

Win 10
VS 2013, VS2015
BeitragVerfasst: Do 25.06.15 21:01 
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,

in der Rechenaufgabe 3*5+7*11 könnt man ja die Aufgabe 3*5 und 7*11 getrennten Threads übergeben, die würden dann auf einem Multicore-Prozessor parallel ausgeführt. Der Hauptthread wartet auf die beiden Unter-Threads und führt dann die Addition aus. Das wäre die schnellste Möglichkeit für die Berechnung - wenn nicht die Threadverwaltung wäre!!!!!


Stimmt so übrigens auch nicht ganz :angel:

Moderne Prozessoren, wie z.B. Haswell, können durchaus mehrere Operationen pro Takt auf einem Kern gleichzeitig erledigen, solange sie unabhängig sind. Deine Rechnung "3*5+7*11" würde also in fünf Takten durchlaufen: 2-4 Zyklen für die Multiplikationen (ob eine oder zwei Multiplikationen: egal, dauert gleich lange) und ein Zyklus für die Addition der beiden Ergebnisse. Interessant fand ich da die Vorträge von Eric Brumer: channel9.msdn.com/Ev...Speakers/eric-brumer insbesondere den hier: channel9.msdn.com/Events/Build/2014/4-587

Zum Thema: Schön, dass ihr es ausprobiert habet. Ich persönlich hätte gedacht, dass ein Thread mehr einmaligen Overhead hat. Aber die 30µs sind eine interessante Größe die ich mir mal merken werde :)

Mangels exe/Delphi kann ich leider keine Werte beisteuern :oops:
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 376
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Do 25.06.15 21:45 
Danke an alle,

jfheins: Das wusste ich nicht. Mein Kleinstbeispiel sollte ja nur das Prinzip verdeutlichen.

Das mit den Timeslices passt hier m. E. nicht ganz. Das wird wohl zutreffen, wenn die CPU voll ist. Wenn meine beiden 30 us-Aufgaben erledigt sind, dann hat die CPU frei. (Und ein paar Kerne sind ohnehin noch geparkt.) Warum sollte Windows dann nicht mal die Events verteilen?

Aber der Tipp ist sehr hilfreich. In einer anderen Anwendung, in der ich alle 8 Kerne zu 90 % auslaste, war mir das Zeitverhalten an einer Stelle nicht plausibel, das könnte an den Timeslices liegen.

Nun lasst es aber zu dieser Frage gut sein. Lieber soll jemand eine neue Frage stellen zu dem Thema.

Viele Grüße
GuaAck
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 25.06.15 22:01 
Nur nebenbei zum Testprogramm:
ausblenden Delphi-Quelltext
1:
  sema := createsemaphore(NIL, initial_wert, 2, pansichar('Sema_Rechne_' + inttostr(getcurrentthreadid MOD 10000)));					
An der Zeile sieht man gut warum so viele beim Umstieg von Delphi 7 usw. auf Delphi 2009 und höher Probleme hatten. ;-)
Das passt nicht zusammen.

Richtig wäre eine dieser Varianten:
ausblenden Delphi-Quelltext
1:
2:
3:
  sema := CreateSemaphore(nil, initial_wert, 2, PChar('Sema_Rechne_' + IntToStr(GetCurrentThreadId MOD 10000)));
  sema := CreateSemaphoreA(nil, initial_wert, 2, PAnsiChar('Sema_Rechne_' + IntToStr(GetCurrentThreadId MOD 10000)));
  sema := CreateSemaphoreW(nil, initial_wert, 2, PWideChar('Sema_Rechne_' + IntToStr(GetCurrentThreadId MOD 10000)));
Die Mischung aus der Standard-Variante von CreateSemaphore mit einem speziellen Parameterwert für die Ansi-Variante (der Cast auf PAnsiChar) verträgt sich nicht. Denn ab Delphi 2009 erwartet diese Standard-Variante einen PWideChar...

Für diesen Beitrag haben gedankt: GuaAck
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 25.06.15 22:43 
user profile iconjfheins hat folgendes geschrieben Zum zitierten Posting springen:

Mangels exe/Delphi kann ich leider keine Werte beisteuern :oops:


32Bit + 64Bit im Anhang.
Einloggen, um Attachments anzusehen!

Für diesen Beitrag haben gedankt: Mathematiker
Mathematiker
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: Do 25.06.15 22:55 
CPU: i5-3230M, 2.6GHz
Hauptthread --- 2 Threads (alle Starteinstellung)
Hathors Programme
64Bit
3,22 ------------ 1,72
32Bit
9,27 ------------ 5,12
Mit Delphi 7 übersetzt
9,58 ------------ 5,42
Mit Delphi 5 übersetzt
9,41 ------------ 5,38
Für mich erstaunlich, wie schnell das bei 64bit ist.

Beste Grüße

_________________
Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Delphi-Laie
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1600
Erhaltene Danke: 232


Delphi 2 - RAD-Studio 10.1 Berlin
BeitragVerfasst: Fr 26.06.15 06:42 
Vielleicht darf ich noch anmerken, daß sich die Multiplikation mehrstelliger Zahlen (reicht, wenn ein Faktor mehrstellig ist) ihrerseits parallelisieren und mithin an mehrere Threads verteilen läßt. Wenn man es darauf anlegt, lassen sich sehr viele Algorithmen bis zum Gehtnichtmehr ziselieren und parallelisieren. Das kann sogar sinnvoll sein, nämlich dann, wenn man diese Simultaneität bzw. Parallelisierbarkeit demonstrieren möchte.
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 376
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Sa 27.06.15 19:06 
Hallo Jaenicke,

das mit Pchar usw. ist für mich sehr hilfreich, bei mir war es busher eher Zufall, welchen PChar ich jeweils genommen habe.

Gru0
GuaAck