Einzelnen Beitrag anzeigen

Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.982 Beiträge
 
Delphi 12 Athens
 
#2

AW: Threads und StringList

  Alt Heute, 01:59
Zunächst einmal zu ein paar Fehlern:
Delphi-Quellcode:
constructor TURLCheckerThread.Create(UrlList: TStrings; CriticalSection: TCriticalSection; OnStatus: TProc<string>; ShouldStop: PBoolean; ResultList: TStrings);
begin
  inherited Create(False);
  FUrlList := UrlList;
  FResultList := ResultList;
  FCriticalSection := CriticalSection;
  FOnStatus := OnStatus;
  FShouldStop := ShouldStop;
  FreeOnTerminate := True;

  {Zähle aktive Threads}
  TThread.Synchronize(nil, procedure
    begin
      Inc(Form1.ActiveThreads);
      Form1.UpdateLabelActiveThreads;
    end);
end;

procedure TURLCheckerThread.UpdateStatus(const Msg: string);
begin
  if Assigned(FOnStatus) then
     TThread.Synchronize(TThread.Current, procedure begin FOnStatus(Msg); end);
end;
Erstens verwendest du TThread.Synchronize in TURLCheckerThread.Create. TURLCheckerThread.Create rufst du aber im Hauptthread auf. Deshalb brauchst du hier keine Synchronisation. In aktuellen Delphiversionen wird das korrekt behandelt, weshalb es hier keinen Fehler gibt.

Zweitens rufst du in UpdateStatus die Synchronisation mit TThread.Synchronize(TThread.Current... auf. Damit kannst du dir die Synchronisation auch sparen, denn wenn du mit dem aktuellen Thread synchronisierst, bleibst du im gleichen Threrad. Wenn du nil verwendest, wird der Code im Hauptthread ausgeführt.

Drittens packst du die Threads nach der Erstellung in ein Array. Du verwendest aber FreeOnTerminate, sprich der Thread wird nach Beendigung seiner Aufgabe automatisch freigegeben. Du weißt aber nicht, wann das passiert. Deshalb darfst du einen solchen Thread nie in eine Variable speichern, damit du nicht aus Versehen darauf zugreifst. Du weißt ja dann gar nicht, ob der Thread noch existiert, so dass das Fehler geben kann.

Viertens ist zwar kein Fehler, aber sehr ungünstig und fast so schlecht wie ein Fehler:
Du greifst aus deiner Threadklasse mit Form1.UpdateLabelActiveThreads auf Form1 zu. Du solltest stattdessen die Threadklasse besser in eine eigene Unit packen und alles, was diese braucht, dorthin übergeben. Dann schaffst du dir keine unnötigen Abhängigkeiten und hast eine bessere Trennung des Ablaufs im Thread.

Nun zum Thema:
Bei Threads muss man sich immer anschauen, was wie viel Zeit benötigt. Wenn man z.B. Threads hat, die einzeln nicht so lange brauchen, muss man aufpassen, dass man für deren Verwaltung nicht zu viel Aufwand betreibt. Denn ansonsten wird die Aufgabe insgesamt mit Threads nicht schneller erledigt als ohne.

In deinem Fall brauchst du viel Zeit, um die URLs zu prüfen. Daher ist der Aufwand für die Listen im Vergleich viel geringer. Deshalb ist es gar kein Problem, wenn jeder Thread eine eigene Ergebnisliste bekommt, die du dann im OnStatus aus dem Thread übergeben bekommst. Und die URL kannst du ja einfach direkt als String übergeben. Denn in der Schleife bei der Erstellung der Threads läuft ja nichts parallel, so dass du einfach direkt auf die URL-Liste zugreifen kannst.

Sprich als Pseudocode:
Delphi-Quellcode:
  for Index := 0 to SpinEditThreads.Value - 1 do
  begin
    TURLCheckerThread.Create(UrlList[i], ...);
    Inc(Form1.ActiveThreads);
    Form1.UpdateLabelActiveThreads;
  end;
So erstellst du aber keine neuen Threads, wenn die ersten URLs abgearbeitet sind. Deshalb wären ein Threadpool oder auch TParallel.For Alternativen.

Du kannst aber auch einfach die Liste auf die Anzahl der Threads verteilen und jedem Thread nicht eine URL geben, sondern eine Liste, die dieser dann abarbeitet. Sprich wenn du 300 URLs hast und 5 Threads möchtest, gibst du jedem Thread eine Liste von 60 URLs.

Das Thema Multithreading ist tatsächlich sehr umfangreich. Das ist nur ein Anfang. Dazu ließe sich noch viel mehr schreiben, aber besser ist glaube ich, wenn du dir das erst einmal anschaust und ggf. Rückfragen stellst.
Sebastian Jänicke
AppCentral

Geändert von jaenicke (Heute um 12:44 Uhr) Grund: Synchronize falsch verstanden
  Mit Zitat antworten Zitat