Autor Beitrag
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Mi 28.09.16 16:45 
Also die Message an sich kommt in dem Hauptthread an aber dort lässt das Flag nur dann den Refresh zu wenn der vorherige zurückgekommen ist.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TfrmWebSiteAnalyser.UpdateURLList;
begin
 if DomainCrawler.URLListQuery.Active and DomainCrawler.DoRefresh then
 begin
  DomainCrawler.DoRefresh := false;
  DomainCrawler.URLListQuery.Refresh;
 end;
end;
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Do 29.09.16 02:35 
Ich habe hier ein Beispiel zusammengestellt, jedoch ist meine Datenbank eine lokale SQLite3 (gesteuert mit ZEOS Komponenten) und das "Parsen" des HTML Dokumentes beschränkt sich auf nur ein Suchmerkmal in ein und dem selben Dokument, in mehrfacher Ausführung.

Dabei wird während des Schreibvorganges der Datensätze, das TDBGrid und nicht dessen TDataSet im Hauptthread aktualisiert.
Die Datensätze purzeln recht flüssig und konstant ins DBGrid.
Das Ergebnis entspricht den Vorgaben des TE.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
type
  TTestThread = class(TThread)
  protected
    procedure Execute; override;
  private
    FIdHttp: TIdHTTP;
    FConnection: TZConnection;
    FQuery: TZQuery;
    FDataSource: TDataSource;
    FUrl: string;
    FDbFile: string;
    procedure ParseText(Source, StrLeft, StrRight: stringvar Destination: string);
  public
    constructor Create(CreateSuspended: Boolean);
    destructor Destroy; override;
    property DataSource: TDataSource read FDataSource;
    property Url: string read FUrl write FUrl;
  end;

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TTestThread.Create(CreateSuspended: Boolean);
begin
  inherited;
  FConnection := TZConnection.Create(nil);
  FQuery := TZQuery.Create(nil);
  FDataSource := TDataSource.Create(nil);
  FIdHttp := TIdHttp.Create(nil);

  FConnection.Protocol:= 'sqlite-3';
  FDbFile := ExtractFilePath(Application.ExeName) + 'MyDatabase.db';
  FConnection.Database := FDbFile;

  FQuery.Active := false;
  FQuery.Connection := FConnection;

  FDataSource.DataSet := FQuery;
end;

destructor TTestThread.Destroy;
begin
  FConnection.Free;
  FQuery.Free;
  FDataSource.Free;
  FIdHttp.Free;
  inherited;
end;

procedure TTestThread.Execute;
var
  sql, html: string;
begin
  // Lokale DB erstellen
  if not FileExists(FDbFile) then
  begin
    FConnection.Connect;
    FConnection.Disconnect;

    // Tabelle erstellen
    sql := 'CREATE TABLE IF NOT EXISTS t_search(id INTEGER PRIMARY KEY AUTOINCREMENT, keywords VARCHAR(255))';
    FQuery.SQL.Text := sql;
    FQuery.ExecSQL;
  end;

  // Html parsen
  html := FIdHttp.Get(Url);
  ParseText(html, '<title>''</title>', html);
  if html = '' then
  begin
    ShowMessage('Nichts gefunden!');
    exit;
  end;

  // Tabelle anzeigen
  sql := 'SELECT * FROM t_search';
  FQuery.SQL.Text := sql;
  FQuery.Open;

  // Datensatz schreiben
  {sql := 'INSERT INTO t_search(keywords) VALUES (:keyword)';
  FQuery.SQL.Text := sql;
  FQuery.Params.ParamValues['keyword'] := html;
  FQuery.ExecSQL;  }

  FQuery.Append;
  FQuery.Edit;
  FQuery.FieldByName('keywords').AsString := html;
  FQuery.Post;
end;

procedure TTestThread.ParseText(Source, StrLeft, StrRight: stringvar Destination: string);
var
  PosLeft, PosRight: Integer;
  s: string;
begin
  PosLeft := Pos(StrLeft, Source);
  PosRight := Pos(StrRight, Source);
  if (PosLeft <> 0and (PosRight <> 0)  then
  begin
    s := Copy(Source, PosLeft + Length(StrLeft),
              PosRight - PosLeft - Length(StrLeft));
    Destination := s;
  end else
    Destination := '';
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  TEST_COUNT = 100;
var
  tests: array of TTestThread;
  i: integer;
begin
  SetLength(tests, TEST_COUNT);
  for i := Low(tests) to High(tests) do
  begin
    tests[i] := TTestThread.Create(true);
    tests[i].FreeOnTerminate := false;
    tests[i].Url := 'http://localhost/PHP_DB_Demo/main.html';
    DBGrid1.DataSource := tests[i].DataSource;
    tests[i].Resume;
    tests[i].WaitFor;
    DBGrid1.Refresh;
  end;
end;

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)

Für diesen Beitrag haben gedankt: NOS
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Do 29.09.16 10:10 
Hi Frühlingsrolle :-)

Hier ergibt sich bei mir die Problematik dass ich in den Threads mehrere Querys habe die bestimmte Teile der Analyse schreiben um nicht jedes mal, bei nur einer query, das prepare und parsen des sql statements und der params zu haben.

Im Moment scheint es so dass es einen Stack Overflow gibt bei langsamen und älteren rechnern. Ich finde nur keinen Ansatz momentan das Problem zu finden.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 18694
Erhaltene Danke: 1620

W10 x64 (Chrome, IE11)
Delphi 10.2 Ent, Oxygene, C# (VS 2015), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 29.09.16 10:59 
Da sollte der Stacktrace ja weiterhelfen. Den bekommst du z.B. mit MadExcept oder Eurekalog.

Für diesen Beitrag haben gedankt: NOS
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Do 29.09.16 11:38 
Hi Jaenicke :-)

probiere ich mal aus
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1166
Erhaltene Danke: 81

Win7
DXE2 Prof, Lazarus
BeitragVerfasst: Do 29.09.16 14:14 
user profile iconNOS hat folgendes geschrieben Zum zitierten Posting springen:
Im Moment scheint es so dass es einen Stack Overflow gibt bei langsamen und älteren rechnern. Ich finde nur keinen Ansatz momentan das Problem zu finden.

Gibt es wirklich einen Stack Overflow? Ich vermute eher das zu viele Nachrichten kommen. Ich kenne ein paar Fälle bei denen das am Ende dann mit einem Stack Overflow endet.
Problem scheint nach wie vor zu sein dass Du an der falschen Stelle entscheidest ob Refresh geht oder nicht.
Du kannst Events aus deinem Thread schicken die anzeigen dass da noch was läuft. Aber Refresh solltest du wirklich via Timer direkt vom Form aus organisieren. Probiers mal ;-)

€: Krankes Quote geheilt.
€2: Schönheit verbessert.

_________________
Solange keine Zeile Code geschrieben ist, läuft ein Programm immer fehlerfrei.
Ich teste nicht, weil ich Angst habe Fehler zu finden.


Zuletzt bearbeitet von Sinspin am Do 29.09.16 15:53, insgesamt 2-mal bearbeitet

Für diesen Beitrag haben gedankt: NOS
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Do 29.09.16 14:25 
Ok .... checke ich gleich mal ab ob das mit einem timer was bringt
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Do 29.09.16 21:09 
user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconNOS hat folgendes geschrieben Zum zitierten Posting springen:
Im Moment scheint es so dass es einen Stack Overflow gibt bei langsamen und älteren rechnern. Ich finde nur keinen Ansatz momentan das Problem zu finden.

Gibt es wirklich einen Stack Overflow? Ich vermute eher das zu viele Nachrichten kommen. Ich kenne ein paar Fälle bei denen das am Ende dann mit einem Stack Overflow endet.
Problem scheint nach wie vor zu sein dass Du an der falschen Stelle entscheidest ob Refresh geht oder nicht.
Du kannst Events aus deinem Thread schicken die anzeigen dass da noch was läuft. Aber Refresh solltest du wirklich via Timer direkt vom Form aus organisieren. Probiers mal ;-)


Also es ist tatsächlich so dass ich durch den Timer keine Stack Overflows mehr habe .... es scheint auch mit dem ResourceOptions.CmdExecTimeout und der Anzahl der Refreshes zu tun zu haben ....
mir ist nur schleierhaft warum es nicht so funzt dass man ein Refresh macht udn danach ein Flag setzt oder was auch immer um festzulegen dass ein neues Refresh gemacht werden kann ... das muss doch gehen
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Do 29.09.16 23:29 
Es muss doch garnicht so umständlich sein. Hast du dich garnicht an meinem Beispiel versucht? :gruebel:
Einloggen, um Attachments anzusehen!
_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)

Für diesen Beitrag haben gedankt: NOS
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Fr 30.09.16 09:22 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Es muss doch garnicht so umständlich sein. Hast du dich garnicht an meinem Beispiel versucht? :gruebel:


Hi und guten Morgen,

aber sicher habe ich mir dein beispiel angeschaut und auch darauf geantwortet (weiter oben). Zum einen ist der Aufbau bei mir aus Performancegründen anders (mehrere TFdQueries für das schreiben in verschiedene Tabellen) und dazu komt noch das Du die Threads ja im eigentlichen Sinne nicht parallel arbeiten hast sondern nacheinander.

Hier gehts aber um Webseiten die jenseits der 200.000 URL's liegen und die Threads laufen alle parallel mehrere Stunden. Da sieht es schon ganz anders aus.
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Fr 30.09.16 09:58 
Auch wenn du es so machst, so landen die Datensätze nicht gleichzeitig in die DB, sondern nacheinander, wie bei mir. Am Ende führt es zum selben Ergebnis, nur ist der Weg ein anderer.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Fr 30.09.16 10:12 
Die Problematik fängt ja da an wo die Datenmenge zu groß wird. Also wenn du dein Beispiel mal so veränderst dass es permanent schreibt und die threads nicht hintereinander ablaufen wirst du sehen dass das mehr probleme macht denke ich.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 18694
Erhaltene Danke: 1620

W10 x64 (Chrome, IE11)
Delphi 10.2 Ent, Oxygene, C# (VS 2015), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 30.09.16 21:13 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Auch wenn du es so machst, so landen die Datensätze nicht gleichzeitig in die DB, sondern nacheinander, wie bei mir.
Doch, bei ihm schreiben mehrere Threads wirklich parallel. Das verzahnt die DB dann natürlich zu einer Sequenz von Einträgen, aber die Daten der einzelnen Threads laufen parallel an der DB auf.
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Fr 30.09.16 21:18 
In dem Fall vielleicht schon, aber bei großen Datenmengen wird das doch zeitkritisch oder bin ich da auf dem Holzweg ? Wenn die Threads dauernd daten in die db schreiben sieht es doch schon anders aus. Außerdem wirkt doch das Connectionpooling von Firebird da auch noch mit rein oder bin ich da auf dem Holzweg ?
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Sa 01.10.16 15:32 
So ... also abstürzen bzw. Stack Overflows gibt es nun nicht mehr .... der Refresh funktioniert auch jeweils nacheinander .... im Moment teste ich in wie weit das die Analysegeschwindigkeit an sich beeinflusst an einer großen URL (bundestag.de)

Ich habe gesehen dass das DBGrid die Datensätze intern irgendwie umstellt oder sehe ich das falsch ? Wenn ich in dem SQL statement kein order by nutze etc. müsste es doch in der reihenfolge des addens angezeigt werden, also inkrementierte ID ... aber es sieht so aus .... sortiert das grid irgendwo ?
Einloggen, um Attachments anzusehen!
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Sa 01.10.16 16:59 
Das dürfte wohl eher an den Threads liegen, so wie es jaenicke beschrieben hat:
Zitat:
[...] Das verzahnt die DB dann natürlich zu einer Sequenz von Einträgen [...]

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Sa 01.10.16 17:55 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Das dürfte wohl eher an den Threads liegen, so wie es jaenicke beschrieben hat:
Zitat:
[...] Das verzahnt die DB dann natürlich zu einer Sequenz von Einträgen [...]


Aber die URL 16530 an 28ter Stelle ? Soviele URLs sind zu dem Zeitpunkt der Analyse noch nicht einmal gefunden und zur DB geadded ... die taucht irgendwann während des aktualisierens auf
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Sa 01.10.16 22:56 
Ich sehe nur dass die ID's etwas durcheinander sind. Die Reihenfolge der Links kenn' ich nicht, und von Bedeutung ist es auch nicht wirklich. Das DBGrid kann nichts dafür. Es spiegelt nur den Inhalt wieder, mehr nicht. Wenn du nichts dem Zufall überlassen würdest, ruf' beim Schreiben der Query, .Append vor .Edit und .Post auf. Somit wird ans zuletzt geschriebene Element, das nächste Element drangehängt.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)

Für diesen Beitrag haben gedankt: NOS
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 183
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Sa 01.10.16 23:12 
Werde ich morgen mal checken .... danke und gute nacht :-)