![]() |
Multithreading
Hallo kann mal wer einen Blick auf meinen Code werfen - irgendwo habe ich da einen Denkfehler.
Das ist meine Threadklasse
Delphi-Quellcode:
Und so rufe ich das mit einer Art Threadpool auf
type
TTestThread = class(TThread) protected fWaitFinish : THandle; fResumeEvent : THandle; procedure Execute; override; public constructor Create(); destructor Destroy; override; end; destructor TTestThread.Destroy; begin CloseHandle(fWaitFinish); CloseHandle(fResumeEvent); inherited; end; constructor TTestThread.Create(); var i : integer; begin fResumeEvent := 0; fWaitFinish := CreateEvent(nil, TRUE, FALSE, nil); FreeOnTerminate := FALSE; inherited Create(TRUE); end; procedure TTestThread.Execute; procedure internalExecute; var i : integer; x : Byte; begin x := 9; for i:=1 to 10000000 do begin x := x xor (Random(9999999) mod 255); end; SetEvent(fWaitFinish); end; begin fResumeEvent := CreateEvent(nil, TRUE, FALSE, nil); repeat internalExecute; if Terminated then break; WaitForSingleObject(fResumeEvent, INFINITE); ResetEvent(fResumeEvent); until Terminated; SetEvent(fWaitFinish); end;
Delphi-Quellcode:
Den Testbutton rufe ich einmal mit einem Thread auf und einmal das er acht Threads machen soll
procedure TfrMDIChild.Button19Click(Sender: TObject);
var maxThreads : integer; tempFunc : TInterpreterFunDesc; hArrWait : array of THandle; threadList : array of TTestThread; function GetIdleThread : integer; var i : integer; begin for i:=0 to maxThreads-1 do if hArrWait[i] = 0 then begin threadList[i] := TTestThread.Create(); hArrWait[i] := threadList[i].fWaitFinish; Result := i; exit; end; repeat Result := WaitForMultipleObjects(length(hArrWait), @hArrWait[0], FALSE, INFINITE); until (Result >= 0) and (Result < maxThreads); Result := Result - WAIT_OBJECT_0; end; procedure InitThreads; var i : integer; begin setlength(threadList, maxThreads); setlength(hArrWait, maxThreads); for i:=0 to maxThreads-1 do hArrWait[i] := 0; end; var i : integer; threadIdx : integer; perfFreq : int64; perfStart : int64; perfEnd : int64; begin QueryPerformanceFrequency(perfFreq); QueryPerformanceCounter(perfStart); maxThreads := TButton(Sender).Tag; InitThreads; for i:=0 to 100 do begin threadIdx := GetIdleThread; if threadList[threadIdx].fResumeEvent = 0 then begin threadList[threadIdx].Resume; end else begin ResetEvent(threadList[threadIdx].fWaitFinish); SetEvent(threadList[threadIdx].fResumeEvent); end; end; QueryPerformanceCounter(perfEnd); setlength(threadList, 0); setlength(hArrWait, 0); QueryPerformanceCounter(perfEnd); Memo1.Lines.Add('Threading ('+IntToStr(maxThreads)+' Threads : '+FormatFloat('0.00', (perfEnd-perfStart) * 1000 / perfFreq)+' ms'); end; Das Ergebnis ist dann
Code:
Was übersehe ich da das er bei 8 gleichzeitigen Threads die Dauer so lange ist? (Die CPU Auslastung geht aber da schön auf fast 100% hoch)
Threading (1 Threads : 4446,57 ms
Threading (8 Threads : 5980,15 ms |
AW: Multithreading
Wie viele Kerne hat die CPU, auf der du das ausführst?
|
AW: Multithreading
Entwicklungsrechner ist ein virtualisierter mit 4 Kerne
Aber auch auf meinem Rechner hier dann direkt die EXE getestet und der hat 8 "echte" Kerne. Bei beiden das gleiche - mit einem Thread ist es am schnellsten |
AW: Multithreading
Hey Hans,
wenn ich deinen Code beim Überfliegen richtig verstanden habe, erzeugst du doch im
Delphi-Quellcode:
Teil immer die gleiche Aufgabe, für egal wie viele Threads. Spich jeder Thread hat die gleich Aufgabe und bei dem 8 Thread Pool kommt dann eben noch der Overhead drauf für das Threadhandeling.
InternalExecute
Oder hab ich da was übersehen? Edit: Code nicht verstanden :oops: |
AW: Multithreading
Wenn er 8 Kerne hat, dann musst du schon sicher stellen, das gar nix anderes läuft, damit er dieselbe Aufgabe 8mal durchführen kann auf 8 Threads, damit er genauso schnell ist, wie die Aufgabe 1mal auszuführen.
Ich habe das bei mit einem 12Kerner versucht bei mir (i7-12700, was nen 12-Kerner mit 8 P-Cores ist) und sehe in etwa die selbe Dauer mit einem oder mit acht Threads. |
AW: Multithreading
JA es soll im prinzip ienfahc 100 mal der code vom internalExecute ausgeführt werden - in dem Fall eine einfachste Version - die nichts anderes macht ausser primitive Berechnungen.
Daher sollte er mit 8 Threads ja meiner Meinung nach 8 mal so schnell sein wie mit einem Thread - okay ganzer Overhead und co aber zumindest 4 mal so schnell. Und nicht wie in meinem Fall das es sogar langsamer ist diese 100 mal internalExecute auszuführen |
AW: Multithreading
Was fisipjm schon schrieb: Solange Du die auszüführende Aufgabe nicht auf mehrere Threads verteilst sondern jeden Thread die komplette Aufgabe machen lässt, wird sich die Laufzeit nicht ändern. Im Gegenteil: Jeder zusätzliche Thread erhöht den Overhead.
Edit: Mist, gepennt. Man sollte nicht kommentieren, wenn man den Code nicht verstanden hat. |
AW: Multithreading
Hmm verstehe ich nicht ganz
Ich möchte 100 mal die funktion internalExecute aufrufen bei einem thread wird der eine Thread das 100 mal aufrufen bei 8 Threads verteilt es sich, und im idealfall muss jeder Thread die funktion nur 12.5 mal aufrufen |
AW: Multithreading
Mir war so, als sei der Zufallsgenerator je Thread unabhängig,
aber wenn es nur einen Globalen gäbe, dann wäre die Sache klar. * in aufgerufenen Funktionen kann eine Synchronisierung drin sein * und dann die Speicherzugriffe ... wenn alle Kerne auf den selben Speicher zugreifen, dann blocken viele CPUs hier auch gern |
AW: Multithreading
Zitat:
Ohne Random verhält es sich nun wie ich es erwarte ... Komisch im Source vom Randsom sieht man keine CriticalSections oder co Aber nun kann ich weiter testen danke |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:54 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz