|
![]() |
|
Registriert seit: 19. Jan 2008 Ort: Brhv 97 Beiträge Delphi 10.2 Tokyo Professional |
#1
Erstmal vielen Dank für die Antworten.
Ich bleibe nun bei meinem ersten Beispiel, und gehe damit weiter. OK, wie gesagt, ich versuche Step by Step mein Code etwas zu verbessern. Erstmal die einfachen Sachen, die mir klar sind und ich verstanden habe, warum es anders muss. Korrigierter Code kommt gleich. Um es übersichtlich zu halten, stelle ich erst mal weitere Fragen. ![]() 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.
Ich erkenne es auch nicht, wieso du vom Array sprichst. Weil, sehe oben : Ich dachte, es betrifft immer nur ein Thread. Bitte erneut um Aufklärung für Non-Pfofi. Mir ist klar, dass ich die StringList mit allen aktiven Threads füttern kann, (das will ich aber nicht) allerdings erkenne ich es nicht wie da ein Array gebildet wird und wie ich dementsprechend die Threads anders terminieren soll. ![]() 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. Das Thema ist recht schwer, ich versuche aber so gut es geht es etwas zu verstehen, es ist aber echt nicht wirklich leicht. ![]() 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.
Delphi-Quellcode:
procedure ButtonAbbruchClick(Sender: TObject);
procedure ButtonEXITClick(Sender: TObject); procedure ButtonStartClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ButtonWeiterClick(Sender: TObject); private { Private-Deklarationen } CriticalSection : TCriticalSection; UrlList : TStringList; ErgebnisListe : TStringList; ActiveThreads : Int64; IdleJobs : Int64; JobsFinished : Int64; procedure UpdateLabelActiveThreads; procedure UpdateLabelJobs; procedure UpdateLabelFinished; public { Public-Deklarationen } end; var Form1: TForm1; ShouldStop: Boolean = False; implementation {$R *.dfm} type TURLCheckerThread = class(TThread) private FUrlList : TStrings; FResultList : TStrings; FCriticalSection : TCriticalSection; FOnStatus : TProc<string>; FShouldStop : PBoolean; protected procedure Execute; override; procedure UpdateStatus(const Msg: string); public constructor Create(UrlList: TStrings; CriticalSection: TCriticalSection; OnStatus: TProc<string>; ShouldStop: PBoolean; ResultList: TStrings); end; { TWorkerThread } 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; end; procedure TURLCheckerThread.UpdateStatus(const Msg: string); begin if Assigned(FOnStatus) then TThread.Synchronize(nil, procedure begin FOnStatus(Msg); end); end; procedure TURLCheckerThread.Execute; var Url : string; Http : TIdHTTP; begin Http := TIdHTTP.Create(nil); try while not Terminated and not FShouldStop^ do begin Url := ''; FCriticalSection.Acquire; try if FUrlList.Count > 0 then begin Url := FUrlList[0]; FUrlList.Delete(0); end; finally FCriticalSection.Release; end; if Url = '' then Break; try Sleep(Random(2000)); {Hier kommt später meine Aufgabe} // Http.Head(Url); FCriticalSection.Acquire; {Keine Ahnung ob es richtig ist, habe aber rausgelesen dass man StringList auf jeden Fall mit CriticalSection absichern soll} try FResultList.Add('OK: ' + Url); {Ergebnis in StringList eintragen} FResultList.Add('Zweite Zeile'); {Ergebnis in StringList eintragen} FResultList.Add('Dritte Zeile'); {Ergebnis in StringList eintragen} finally FCriticalSection.Release; end; // UpdateStatus('OK: ' + Url); {Damit kann ich zB. die Status ON oder OFF ausgeben, oder weglassen und NUR FResult als Ergebnis nutzen} except on E: Exception do UpdateStatus('FAIL: ' + Url + ' - ' + E.Message); end; TThread.Synchronize(nil, procedure begin Dec(Form1.IdleJobs); Form1.UpdateLabelJobs; Inc(Form1.JobsFinished); Form1.UpdateLabelFinished; end); end; finally Http.Free; TThread.Synchronize(nil, procedure begin Dec(Form1.ActiveThreads); Form1.UpdateLabelActiveThreads; end); end; end; procedure TForm1.FormDestroy(Sender: TObject); begin FreeAndNil(CriticalSection); FreeAndNil(ErgebnisListe); FreeAndNil(UrlList); end; procedure TForm1.ButtonStartClick(Sender: TObject); var Threads : array[0..99] of TURLCheckerThread; Index : Integer; begin if Assigned(CriticalSection) then FreeAndNil(CriticalSection); {Falls ich nach Cancel noch mal Start drücke statt Weiter} if Assigned(UrlList) then FreeAndNil(UrlList); {Falls ich nach Cancel noch mal Start drücke statt Weiter} UrlList := TStringList.Create; CriticalSection := TCriticalSection.Create; ShouldStop := False; for Index := 1 to 100 do begin URLList.Add('http://google.com/' + IntToStr(Index)); end; LabelJobs.Caption := '100'; LabelIdle.Caption := '100'; IdleJobs := 100; JobsFinished := 0; ErgebnisListe := TStringList.Create; for Index := 1 to SpinEditThreads.Value do begin Threads[Index] := TURLCheckerThread.Create(UrlList, CriticalSection, procedure(Msg: string) begin RichEditLog.Lines.Add(Msg); {Ergebnis als String} RichEditLog.Lines.Add(ErgebnisListe.Text); {Ergebnis als StringList} ErgebnisListe.Clear; {Nicht vergessen, sonst wird die StringList immer weiter befüllt} end, @ShouldStop, ErgebnisListe); {Zähle aktive Threads} Inc(ActiveThreads); LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; end; procedure TForm1.ButtonWeiterClick(Sender: TObject); var Threads : array[0..99] of TURLCheckerThread; Index : Integer; begin ShouldStop := False; for Index := 1 to SpinEditThreads.Value do begin Threads[Index] := TURLCheckerThread.Create(UrlList, CriticalSection, procedure(Msg: string) begin RichEditLog.Lines.Add(Msg); {Ergebnis als String} RichEditLog.Lines.Add(ErgebnisListe.Text); {Ergebnis als StringList} ErgebnisListe.Clear; {Nicht vergessen, sonst wird die StringList immer weiter befüllt} end, @ShouldStop, ErgebnisListe); {Zähle aktive Threads} Inc(ActiveThreads); LabelActiveThreads.Caption := IntToStr(ActiveThreads); end; end; procedure TForm1.ButtonAbbruchClick(Sender: TObject); begin ShouldStop := True; end; procedure TForm1.UpdateLabelActiveThreads; begin LabelActiveThreads.Caption := IntToStr(ActiveThreads); {Das war eigentlich nur ein Versehen mit Synchronize. Es war schon spät und viel Stoff für einen Abend :)} end; procedure TForm1.UpdateLabelJobs; begin LabelIdle.Caption := IntToStr(IdleJobs); end; procedure TForm1.UpdateLabelFinished; begin LabelFinished.Caption := IntToStr(JobsFinished); end; procedure TForm1.ButtonEXITClick(Sender: TObject); begin ShouldStop := True; Close; end; |
![]() |
Themen-Optionen | Thema durchsuchen |
Ansicht | |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
LinkBack |
![]() |
![]() |