AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Threads die wieder andere Threads aufrufen in einer schleife
Thema durchsuchen
Ansicht
Themen-Optionen

Threads die wieder andere Threads aufrufen in einer schleife

Ein Thema von Votum · begonnen am 27. Mai 2010 · letzter Beitrag vom 27. Mai 2010
Antwort Antwort
Seite 1 von 2  1 2      
Votum

Registriert seit: 27. Mai 2010
3 Beiträge
 
#1

Threads die wieder andere Threads aufrufen in einer schleife

  Alt 27. Mai 2010, 14:33
Hallo Liebe Community, meine erster Post hier aber ich hoffe ihr helfft mir trotzdem.

Ich versuche seid gestern einen Webcrawler zu schreiben. Dieser soll Links ausgeben und in eine Listbox ausgeben. Das klappt auch supper. Da er aber auch die unterebenen durchsuchen soll, erstelle ich für jeden Link einen weiteren Thread der die Links der 2 ebene Parst und überprüft ob diese schon in der Listbox vorhanden sind.Danach soll es weiter zur 3. Ebene gehen. Also erstellt der Thread sich rekursiv weiter. So lange bis er keine neuen Links mehr findet.

Mein Problem: Ab 150 Threads wird entweder das Programm grottig langsam oder die Page geht down.

Daher will ich die Anzahl der Threads begrenzen. Leider ist das nicht so einfach da ich ja nicht eifnach sagen kann so stop da es sonst ein Deadlock gibt.

Hat jemand eine Idee?


Hier noch mein bisheriger Quellcode:

Delphi-Quellcode:
unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, JvComponentBase, StdCtrls, idhttp, strutils;




type
  THTTPThread = class(TThread)
  private
    FURL: String;
    HTTP: tidhttp;
    FListText: String;
  protected
    procedure DoWriteListBox;
    procedure DoUpdateThreadCount;
  public
    procedure Execute; override;
    constructor Create(URL: String);
    destructor Destroy; override;
  published
    property URL: String read FURL;
  end;

  TArrayofstring = array of string;
  TForm3 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    ListBox1: TListBox;
    Memo1: TMemo;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;


var
  Form3: TForm3;
  host:string;
  ccount: integer = 0;

implementation

{$R *.dfm}

constructor THTTPThread.Create(URL: String);
begin
  inherited Create(true);
  FreeOnTerminate := true;
  FURL := URL;
  Resume;
end;


function FindInString(Text, SearchFrom, SearchTo: string; FirstOnly: Boolean; var Return: TArrayOfString): Boolean;
var
  i: Integer;
  FoundString: string;
begin
  Result := False;
  SetLength(Return, 0);
  i := Pos(SearchFrom, Text);
  while i > 0 do
  begin
    Result := True;
    i := i + Length(SearchFrom);
    FoundString := Copy(Text, i, PosEx(SearchTo, Text, i) - i);
    SetLength(Return, Length(Return) + 1);
    Return[High(Return)] := FoundString;
    Delete(Text, 1, i);
    i := Pos(SearchFrom, Text);
    if FirstOnly then
      Break;
  end;
end;



procedure TForm3.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  host := edit1.Text;
  THTTPThread.Create(host);
end;




destructor THTTPThread.Destroy;
begin
  inherited;
end;

procedure THTTPThread.DoUpdateThreadCount;
begin
  Form3.label1.Caption := IntToStr(CCount);
end;

procedure THTTPThread.DoWriteListBox;
begin
  Form3.ListBox1.Items.Add(FListText);
end;

procedure THTTPThread.Execute;
  var
i, j,x,position:integer ;
http:tidhttp;
links:tarrayofstring;
s: string;
found: boolean;
begin

inc(ccount);
synchronize(DoUpdateThreadCount);

HTTP := TIdHTTP.Create(nil);
http.HandleRedirects:= true;
try
  s := http.Get(URL);
except
  S := '';
end;

   findinstring(s,'href="','"',false,links);
   for I := 0 to High(Links) do
   begin
        FListText := links[i];
           if Copy(FListText, 1, 4) <> 'httpthen
            begin

              FListText := host + FListText;

              // und hier mit nem if oder ?
              found := false;
              for j := 0 to form3.ListBox1.items.count -1 do
              begin
                if form3.listbox1.items[j] = FListText then
                begin
                  found := true;
                  break;
                end;
              end;
              if not found then
              begin
              THTTPThread.Create(FListText);
              Synchronize(DoWriteListBox);
              end;
            end else if Pos(Host, FListText) > 0 then
            begin
              found := false;
              for j := 0 to form3.ListBox1.items.count -1 do
              begin
                if form3.listbox1.items[j] = FListText then
                begin
                  found := true;
                  break;
                end;
              end;
              if not found then
              begin
              THTTPThread.Create(FListText);
              Synchronize(DoWriteListBox);
              end;
            end;



   end;
   dec(ccount);
synchronize(DoUpdateThreadCount);
end;
  Mit Zitat antworten Zitat
dominikkv

Registriert seit: 30. Sep 2006
Ort: Gundelfingen
1.109 Beiträge
 
Delphi 2007 Professional
 
#2

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 14:40
Zitat von Votum:
Daher will ich die Anzahl der Threads begrenzen. Leider ist das nicht so einfach da ich ja nicht eifnach sagen kann so stop da es sonst ein Deadlock gibt.
Warum?
Delphi-Quellcode:
// Execute
begin
  while ccount > 10 do
    sleep(500);

  inc(ccount);
  // ...
Dominik
Wer anderen eine Grube gräbt, hat ein Gruben-Grab-Gerät!
  Mit Zitat antworten Zitat
taveuni

Registriert seit: 3. Apr 2007
Ort: Zürich
526 Beiträge
 
Delphi 11 Alexandria
 
#3

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 14:42
Hallo,

Threadpool heisst das Zauberwort.
Du erstellts eine (konfigurierbare) Anzahl Threads.
Des weiteren eine Jobliste für Deine auszuführenden Aktionen.
Jeder Thread welcher seine aktuelle Aufgabe beendet hat nimmt sich den
nächsten aus der Jobliste.

Die Zugriffe auf die Liste müssen natürlich z.b. mit einer CritcalSection abgesichert werden.
Die obige Aussage repräsentiert meine persönliche Meinung.
Diese erhebt keinen Anspruch auf Objektivität oder Richtigkeit.
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 14:42
@dominikkv Das kann ja nicht funktionieren. Beispiel:
Thread 1 findet 10 Links. In der Schleife erstellt er nun 3 weitere Instanzen von sich selbst (4 nehmen wir mal ans Begrenzung an). Die erstellten Instanzen parsen die übergebenen Links. Da jetzt aber schon insgesamt 4 Threads laufen, warten die Child Threads bis in alle Ewigkeit, wobei der Thread 1 ebenfalls bis in alle Ewigkeit darauf wartet, dass einer der Child Threads beendet wird.
DeadLock
  Mit Zitat antworten Zitat
Benutzerbild von rollstuhlfahrer
rollstuhlfahrer

Registriert seit: 1. Aug 2007
Ort: Ludwigshafen am Rhein
1.529 Beiträge
 
Delphi 7 Professional
 
#5

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 14:43
HI und Herzlich Willkommen in der DP

zuerst: Threads arbeiten GLEICHZEITIG. Das heißt, sie teilen sich die CPU-Last untereinander auf. Und wenn du deine CPU-Last auf 150 Rechner (Threads) verteilen müsstest, wäre dein Rechner auch lahm.
"die Page geht down" - ist klar. Fällt übrigens unter DOS-Angriff.
Dann verwendest du in deinem Code inc() und dec() für die Zählvariable. Dies ist aber nicht richtig. Wenn 2 Threads gleichzeitig die Variable erhöhen wollen, was durchaus vorkommt bei so vielen, wird die Variable nur um 1 erhöht. (2 Zugriffe, die beide dann erhöhen und ihren Wert ungeprüft zurückschreiben. Dafür bietet Delphi auch bestimmte Funktionen an. Ich würde das aber mit einer Semaphore lösen. (Ist threadsicher). Einer Semaphore kannst du sagen, dass sie eine bestimmte Prozedur nur x-Mal gleichzeitig ausführen darf. Alle die dann die Prozedur ausführen möchten, müssen so lange warten, bis wieder einer fertig ist,
Zum Zählen: Delphi-Referenz durchsuchenInterlockedIncrement und Delphi-Referenz durchsuchenInterlockedDecrement
Die Semaphore: hier

Eine CriticalSection würde ich nicht empfehlen, da diese auch die anderen Threads anhällt.

Bernhard
Bernhard
Iliacos intra muros peccatur et extra!
  Mit Zitat antworten Zitat
Votum

Registriert seit: 27. Mai 2010
3 Beiträge
 
#6

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 14:50
Zitat von rollstuhlfahrer:
HI und Herzlich Willkommen in der DP

zuerst: Threads arbeiten GLEICHZEITIG. Das heißt, sie teilen sich die CPU-Last untereinander auf. Und wenn du deine CPU-Last auf 150 Rechner (Threads) verteilen müsstest, wäre dein Rechner auch lahm.
"die Page geht down" - ist klar. Fällt übrigens unter DOS-Angriff.
Dann verwendest du in deinem Code inc() und dec() für die Zählvariable. Dies ist aber nicht richtig. Wenn 2 Threads gleichzeitig die Variable erhöhen wollen, was durchaus vorkommt bei so vielen, wird die Variable nur um 1 erhöht. (2 Zugriffe, die beide dann erhöhen und ihren Wert ungeprüft zurückschreiben. Dafür bietet Delphi auch bestimmte Funktionen an. Ich würde das aber mit einer Semaphore lösen. (Ist threadsicher). Einer Semaphore kannst du sagen, dass sie eine bestimmte Prozedur nur x-Mal gleichzeitig ausführen darf. Alle die dann die Prozedur ausführen möchten, müssen so lange warten, bis wieder einer fertig ist,
Zum Zählen: Delphi-Referenz durchsuchenInterlockedIncrement und Delphi-Referenz durchsuchenInterlockedDecrement
Die Semaphore: hier

Eine CriticalSection würde ich nicht empfehlen, da diese auch die anderen Threads anhällt.

Bernhard

Das dies ein Dos Angriff ist, ist mir durchaus bewust jedoch ist ein Http Flood nicht alzu wirksam.... Falsches Thema

Wie Zacherl gesagt hat geht es schlecht mit maximal 4 Threads wenn ein Thread sich weiter aufruft, kann er ja nicht weitermachen.
Wie arbeitet der Threadpool und wie die Semaphore dann ?
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#7

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 14:51
Hat man bei der Semaphore nicht das selbe Problem, dass es zu einem DeadLock kommt, da die Threads ja rekursiv arbeiten? Ist ja praktisch genauso, wie es dominikkv beschrieben hatte, nur etwas eleganter.
  Mit Zitat antworten Zitat
Benutzerbild von rollstuhlfahrer
rollstuhlfahrer

Registriert seit: 1. Aug 2007
Ort: Ludwigshafen am Rhein
1.529 Beiträge
 
Delphi 7 Professional
 
#8

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 14:57
nein hat man nicht. Man kann den Thread erzeugen, doch der fängt halt sofort an zu warten, dass ihm ein anderer Platz macht. -> Der Thread wird erzeugt und gestartet. Die erste Aktion dieses Threads ist nur, dass er mal nachfrägt, ob er darf und wenn nicht halt solange nichts tut, bis er darf. Wenn man die neuen Threads startet, kann man ja getrost auf fertig schalten, da die restlichen Threads dann schneller arbeiten können. Der Thread 1. Ordnung soll nicht auf die Threads höherer Ordnung warten, sondern diese starten und sich dann selbst beenden. So hat man zwar auch mal mehr als 150 Threads aktiv, nur machen die zu vielen alle nichts.

Wobei das Konzept mit den Worker-Threads auch nicht schlecht ist. Der Thread parst eine Seite und erstellt für jeden Link einen Job. Ist er fertig, frägt er die Job-Warteschlange, ob welche da sind. Sind welche da, wird der oberste genommen und abgearbeitet. Und so weiter. Dieser Vorgang ist sehr gut skalierbar. Vorteil hierbei ist halt, dass man die Anzahl der vorhandenen Threads absolut begrenzen kann und hat keine schlafenden Threads. Erst wenn alle fertig sind, schaltet man alle zusammen ab und fertig ist die Aufgabe.

Bernhard
Bernhard
Iliacos intra muros peccatur et extra!
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#9

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 15:05
Finde das ThreadPool Konzept hier auch sinnvoller. Semmaphore war auch meine erste Idee, aber da hat man halt entweder das von mir beschriebene Problem oder die Tatsache, dass du zwar die HTTP Requests limitierst, aber nicht die Threads ansich (wenn man es so macht wie du es eins weiter oben beschreibst).
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#10

Re: Threads die wieder andere Threads aufrufen in einer schl

  Alt 27. Mai 2010, 17:18
Die rekursive Technik ist bei einem Webcrawler nicht ratsam.
Man braucht stattdessen zwei Listen:
a.) besuchte URLs
b.) noch nicht besuchte URLS
Die Listen müssen durch Semaphoren oder ähnliche Sperrmechanismen geschützt werden.
Dann startet man z.B. 5 Threads.
Alle Threads machen das Gleiche;
1.) sie entnehmen aus Liste b.) eine URL (wenn Liste b. leer ist: Sleep(1000))
2.) besuchen die URL und schreiben sie in Liste a.)
3.) extrahieren alle gefundenen URLs
4.) prüfen für jede URL, ob sie nicht schon in Liste a.) ist
und hängen sie an Liste b.) an

Man kann das Ganze auch mit einer Liste machen.
Dabei muss für jede URL in der Liste zusätzlich ein Status (besucht oder nicht besucht) geführt werden.
Wenn man schon dabei ist, kann man auch noch den HTTP Resultcode (z.B. 404) in der Liste speichern.
Andreas
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 15:29 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