| 
| Autor | Beitrag |  
| GuaAck 
          Beiträge: 378
 Erhaltene Danke: 32
 
 Windows 8.1
 Delphi 10.4 Comm. Edition
 
 | 
Verfasst: Sa 20.06.15 22: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 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: So 21.06.15 06: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  
          Beiträge: 378
 Erhaltene Danke: 32
 
 Windows 8.1
 Delphi 10.4 Comm. Edition
 
 | 
Verfasst: Di 23.06.15 22: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):
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 
 |      FOR i := 1 TO anz_schleifena DOBEGIN
 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 
          Beiträge: 1654
 Erhaltene Danke: 244
 
 WIN10,PuppyLinux
 FreePascal,Lazarus
 
 | 
Verfasst: Do 25.06.15 08:55 
 
Hallo,
 die Daten von   GuaAck  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 
          Beiträge: 3661
 Erhaltene Danke: 604
 
 Win 8.1, Win 10 x64
 Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
 
 | 
Verfasst: Do 25.06.15 15: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
 
 
 
 
 | 
Verfasst: Do 25.06.15 16: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 
          Beiträge: 918
 Erhaltene Danke: 158
 
 Win 10
 VS 2013, VS2015
 
 | 
Verfasst: Do 25.06.15 20:01 
 
	  |  GuaAck hat folgendes geschrieben  : |  	  | 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     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    |  |  |  
| GuaAck  
          Beiträge: 378
 Erhaltene Danke: 32
 
 Windows 8.1
 Delphi 10.4 Comm. Edition
 
 | 
Verfasst: Do 25.06.15 20: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 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Do 25.06.15 21:01 
 
Nur nebenbei zum Testprogramm: 		                       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: 		                       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
 
 
 
 
 | 
Verfasst: Do 25.06.15 21:43 
 
Einloggen, um Attachments anzusehen!
 Für diesen Beitrag haben gedankt: Mathematiker
 |  |  |  
| Mathematiker 
          Beiträge: 2622
 Erhaltene Danke: 1448
 
 Win 7, 8.1, 10
 Delphi 5, 7, 10.1
 
 | 
Verfasst: Do 25.06.15 21: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 
          Beiträge: 1600
 Erhaltene Danke: 232
 
 
 Delphi 2 - RAD-Studio 10.1 Berlin
 
 | 
Verfasst: Fr 26.06.15 05: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  
          Beiträge: 378
 Erhaltene Danke: 32
 
 Windows 8.1
 Delphi 10.4 Comm. Edition
 
 | 
Verfasst: Sa 27.06.15 18: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
 |  |  |  |