AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Multithreading

Ein Thema von Gruber_Hans_12345 · begonnen am 24. Jul 2023 · letzter Beitrag vom 25. Jul 2023
Antwort Antwort
Seite 2 von 3     12 3      
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#11

AW: Multithreading

  Alt 24. Jul 2023, 15:32
Wenn es eine globale Variable ist, dann streiten sich die Kerne darum.

Aber mir war so, als wären es Threadvars ...


[edit]
Bin erschreckt, aber ErrorAddr und RandSeed sind wirklich var anstatt threadvar
$2B or not $2B
  Mit Zitat antworten Zitat
Gruber_Hans_12345

Registriert seit: 14. Aug 2004
1.439 Beiträge
 
Delphi 2007 Professional
 
#12

AW: Multithreading

  Alt 24. Jul 2023, 15:52
Hmmm blöd gefragt ich dachte wenn es eine 0815 globale Variable ist, dann greifen die Threads einfach direkt darauf zu, und es kann passieren das da dann Müll rauskommt wenn einer schreibt und einer liest und nicht das sich das ganze dann so verhält wie wenn es in einer criticalsection stehen würde?

dh meiner Meinung nach dürfte eine "normale" variable den Thread nicht verlangsamen sondern es kann passieren das irgendwelche komischen Fehler passieren (wenn die nicht in einer CriticalSection sind)
Gruss Hans

2B or not 2B, that is FF

Geändert von Gruber_Hans_12345 (24. Jul 2023 um 15:58 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#13

AW: Multithreading

  Alt 24. Jul 2023, 16:03
Das Problem entsteht durch die unterschiedlichen Caches der Kerne. Die CPU liest ja nicht von und schreibt ja nicht in den tatsächlichen RAM-Bereich, sondern wickelt das über den Cache ab. Dazu wird ein Bereich des RAM in den Cache transferiert (die sogenannte Cache Line) und später wieder geschrieben. Die dabei unweigerlich entstehenden Zugriffsprobleme werden durch das Sperren des zugehörigen RAM-Bereich vermieden. Deswegen müssen die Kerne manchmal eben warten - auch beim Lesen.

Wegen der Größe der Cache Line (i.d.R. 64 Bytes) kommt der Effekt auch zum tragen, wenn nicht mal nur dieselbe Variable verwendet wird, sondern sich z.B. auch zwei Variablen in derselben Cache Line befinden.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#14

AW: Multithreading

  Alt 24. Jul 2023, 16:03
Die Threads prinzipiell ja, außer im Maschinencode/Assembler gibt man z.B. LOCK an ( MOV a, b -> LOCK MOV a, b ).

Aber dennoch kann nicht jeder Thread Kern einfach so gleichzeitig auf jegliche "externe" Hardware zugreifen, wie z.B. den RAM.

zugeteilte Speicherseiten, vorhandener Cache Cacheline usw ... macht jeder Prozessor-Architektur eventuell auch noch jeweils anders.
Es gibt ja auch nicht für jeden Kern ein eigenes Kabel zu jedem Speicherchip.



Oder anders gesagt, so lange jeder Thread möglichst GARNICHTS mit anderen Threads teilt, dann ist es optimal. (bzw. auch nichts, was nur zufällig in der Nähe liegt)
$2B or not $2B

Geändert von himitsu (24. Jul 2023 um 16:07 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.027 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#15

AW: Multithreading

  Alt 24. Jul 2023, 16:09
... im Source vom Randsom ...
OT: Putziger Verschreiber

Zum Thema: Davon abgesehen, dass Random nicht threadsafe ist, hast du hier den klassischen Fall von Code, dessen Multithreadgeschwindigkeit davon gebremst wird, dass shared memory immer übern RAM zu jedem Kern wandern muss.

Auch wenn hier RandSeed, was innerhalb von Random genutzt wird, nicht irgendwie abgesichert wird, ist es doch so, dass jeder Schreibvorgang der CPU signalisiert, dass der Speicher geschrieben wurde, was dazu führt, dass jeder andere Kern, der diesen Wert liest, ihn erst wieder aus dem RAM lesen muss. In deinem Fall führt das dazu, dass die verschiedenen Kerne massiv davon gebremst werden, dass der Wert dieser globalen Variable tausendfach über den RAM zwischen den Kernen hin und her wandert.

Im VTune kann man das sehr schön sehen - siehe Anhang
Miniaturansicht angehängter Grafiken
storebound.jpg  
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (24. Jul 2023 um 16:12 Uhr)
  Mit Zitat antworten Zitat
Gruber_Hans_12345

Registriert seit: 14. Aug 2004
1.439 Beiträge
 
Delphi 2007 Professional
 
#16

AW: Multithreading

  Alt 24. Jul 2023, 16:28
Okay Danke das ist echt "krass" das durch den Cache das sooo extremst langsam wird dann.

jeweils 100 Durchgänge auf 8 Kerne - dh mit 8 Threads dauert ein einzelner Durchgang ca 16 mal so lange - (er sollte ja 8 mal schneller sein und braucht doppelt so lang)

Threading (1 Threads) : 3199,55 ms
Threading (2 Threads) : 5985,58 ms
Threading (4 Threads) : 6630,61 ms
Threading (8 Threads) : 6957,30 ms
Gruss Hans

2B or not 2B, that is FF
  Mit Zitat antworten Zitat
Gruber_Hans_12345

Registriert seit: 14. Aug 2004
1.439 Beiträge
 
Delphi 2007 Professional
 
#17

AW: Multithreading

  Alt 24. Jul 2023, 16:43
Hab jetzt nur zum Gegencheck den Ransom ähmm Random als lokal funktion eingebaut

Delphi-Quellcode:
procedure internalExecute;
    var
        i : integer;
        x : Byte;
        dummy : int64;
        RandSeed : integer;

        function myRandom(const ARange: Integer): Integer;
        asm
        {     ->EAX     Range   }
        {     <-EAX     Result  }
                PUSH EBX
                XOR EBX, EBX
                IMUL EDX,[EBX].RandSeed,08088405H
                INC EDX
                MOV [EBX].RandSeed,EDX
                MUL EDX
                MOV EAX,EDX
                POP EBX
        end;
        
    begin
        QueryPerformanceCounter(dummy);
        RandSeed := dummy;

        x := 9;
        for i:=1 to 1000000 do begin
            x := x xor (myRandom(23223) mod 255);
            //x := x xor (i mod 255);
        end;
        //*)
        SetEvent(fWaitFinish);
    end;
und siehe da nun stimmen die Zeiten zu dem was ich mir vorgestellt habe

Code:
Threading (1 Threads : 3289,73 ms
Threading (2 Threads : 1670,74 ms
Threading (4 Threads : 851,50 ms
Threading (8 Threads : 426,44 ms
Damit ich es nochmal verstehe das genau das das Problem ist.

Kern 1 lädt die 64Byte wo die variable RandSeed ist in die CacheLine des Kern1
Kern 2 ... Kern 4 machen das gleiche
da nun einer der Kerne die Variable Randseed ändert, muss der Kern nun die 64Byte aus der CacheLine wieder zurück in den RAM speichern - und dabei markiert er bei allen anderen Kernen nun das die 64 Byte die die anderen Kerne in der Cacheline haben ungültig sind und diese müssen die nun erneut laden.
  1. Das passiert aber nur wenn der Kern auch Daten ändert, ein nur lesen wäre kein Problem gewesen
  2. Je mehr Kerne da nun das ausgeführt hätten, desto langsamer würde das werden (die Anzahl der Threads ist nebensächlich, da wenn 10 Threads auf einem Kern laufen es ja auch nur eine CacheLine gibt) nur die echten Kerne die auch eine CacheLine haben zählen hier
  3. Wie sicher ist die 64Byte Grenze, und wie kann man das im echten Leben dann sicherstellen das die Variablen sich nicht überschneiden?
Gruss Hans

2B or not 2B, that is FF
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#18

AW: Multithreading

  Alt 24. Jul 2023, 16:57
Inzwischen kann man in Delphi ein eigenes Random registrieren.
Dort könnte man Eines mit TheadVar bauen. (und wenn noch RandSeed=0, dann darin zuerst noch ein Randomize)
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#19

AW: Multithreading

  Alt 24. Jul 2023, 17:08
System.TMonitor hat das in CacheLineSize stehen, aber da kommt man wegen strict protected nicht so einfach ran. Intern wird das benutzt, damit ein TMonitor Record immer mindestens so groß ist wie eine Cache Line.

Du kannst dir aber den entsprechenden Code in GetCacheLineSize oder GetCacheSize abgucken.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#20

AW: Multithreading

  Alt 24. Jul 2023, 17:24
Wie läuft es mit den Zeiten, wenn SetThreadAffinityMask(GetCurrentThread {oder Self.Handle}, $00000001); als Erstes im Execute, mit originalem Random.

Gilt nur, wenn du maximal 64 Kerne hast, sonst fängt man eventuell auch noch mit Prozessorgruppen an.
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz