Autor Beitrag
NOS1971
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 193

Windows 8.1 PRO 64 Bit
Delphi XE7 Professional
BeitragVerfasst: Do 24.07.14 13:25 
Hallo zusammen,

ich habe ein Problem eine Connection Definiton zu erzeugen für meine multithreaded anwendung. ich nutze folgenden code und es erscheint die im anhang sichtbare fehlermeldung obwohl ich alles laut doku mache.

ausblenden 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:
 // check if connection definition exists
 if FDManager.IsConnectionDef(ConDefName) then
 begin
  FDManager.DeleteConnectionDef(ConDefName);
 end;
 // create connection and add it
 condef := TStringList.Create;
 condef.Add('Database=' + FResultDataBaseFileName);
 condef.Add('SharedCache=False');
 condef.Add('LockingMode=Normal');
 condef.Add('Synchronous=Full');
 condef.Add('LockingMode=Normal');
 condef.Add('CacheSize=60000');
 condef.Add('BusyTimeOut=30000');
 condef.Add('Pooled=True');
 condef.Add('POOL_MaximumItems=' + IntToStr(FMaxThreadPoolCount + 1));
 FDManager.AddConnectionDef(ConDefName,'SQLite',condef);

 .
 .
 .
 
 // set fdmanager active
 FDManager.Active := True; 

 .
 .
 .

 //dann kommt das erzeugen der threads


Code aus dem thread:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
var
 oConn: TFDConnection;
begin
 FreeOnTerminate := False;
 oConn := TFDConnection.Create(nil);
 oConn.ConnectionDefName := 'SQLite_Threaded_Pooled';
 try
  oConn.Connected := True;
  while not Terminated do
  begin


  end;
 finally
  oConn.Free;
 end;
end;
Einloggen, um Attachments anzusehen!
zuma
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 660
Erhaltene Danke: 21

Win XP, Win7, Win 8
D7 Enterprise, Delphi XE, Interbase (5 - XE)
BeitragVerfasst: Do 24.07.14 13:56 
ich hab keine Ahnung von Firedac, aber könnte es sein,
das du im oberen Beispiel deine Connection 'SQLite' mit ConDefName (was auch immer drin steht) benennst
und im unteren Beispiel aber versuchst, eine Connection mit dem Namen 'SQLite_Threaded_Pooled' zu verwenden ?
evtl. besser immer ConDefName nutzen ?
klingt für mich so, als könne man da mehrere Connections ablegen und
dann wählen (über den Namen der einzelnen Connections), welche man nehmen will ?
falls ich völlig daneben lieg, einfach diesen Post ignorieren :mrgreen:

zuma

_________________
Ich habe nichts gegen Fremde. Aber diese Fremden sind nicht von hier! (Methusalix)
Warum sich Sorgen ums Leben machen? Keiner überlebts!

Für diesen Beitrag haben gedankt: NOS1971
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 24.07.14 13:57 
Ich weiß nicht warum du die Verbindungsdefinition per Stringliste hinzufügst. Wir machen das so direkt:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
var
  oDef: IFDStanConnectionDef;
begin
  oDef := FDManager.ConnectionDefs.FindConnectionDef('SQLite_Threaded_Pooled');
  if not Assigned(oDef) then
    oDef := FDManager.ConnectionDefs.AddConnectionDef;
  oDef.Name := 'SQLite_Threaded_Pooled';
  oDef.DriverID := 'SQLite';
  oDef.Database := FResultDataBaseFileName;
  oDef.UserName := ...;
  oDef.Password := ...;
  oDef.Apply;


user profile iconzuma hat folgendes geschrieben Zum zitierten Posting springen:
ich hab keine Ahnung von Firedac, aber könnte es sein,
das du im oberen Beispiel deine Connection 'SQLite' mit ConDefName (was auch immer drin steht) benennst
und im unteren Beispiel aber versuchst, eine Connection mit dem Namen 'SQLite_Threaded_Pooled' zu verwenden ?
SQLite ist der Name des Treibers.

Für diesen Beitrag haben gedankt: NOS1971
NOS1971 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 193

Windows 8.1 PRO 64 Bit
Delphi XE7 Professional
BeitragVerfasst: Do 24.07.14 17:07 
HI,

ok .. habe ich so umgebaut .. so ist die verbindung nicht mehr provate sondern persistent ... aber der fehler lag woander ...

Viele dank :-)
NOS1971 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 193

Windows 8.1 PRO 64 Bit
Delphi XE7 Professional
BeitragVerfasst: Do 24.07.14 17:26 
Das funktioniert soweit einwandfrei ....

nun bleibt nur noch das problem das wenn ich mehr als einen thread erzeuge die threads nicht mehr korrekt beendet werden und das proggi komplett im nirvana hängt .... ich habs ja shcon aus dem websitespider rausgenommen um mich diesem problem zu widmen aber es haut nicht hin

vielleicht seht ihr hier die kleinigkeit die das problem verursacht ... und ich tippe mal dass es auch ne kleinigkeit ist

hier das hauptobjekt

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:
{ TMultiThreadedWebAnalyser }

constructor TMultiThreadedWebAnalyser.Create;
begin
  inherited Create;
 // create variables, structures and objects
 ResultURLDictionary := TObjectDictionary<string, TURLNodeTreeData>.Create([doOwnsValues]);
 ProgressData := TProgressData.Create;
end;

destructor TMultiThreadedWebAnalyser.Destroy;
begin
 // empty dictionary
 ResultURLDictionary.Free;
 ResultURLDictionary := nil;
 // empty and free progressdata
 FProgressData.Free;
 FProgressData := nil;
  inherited;
end;

procedure TMultiThreadedWebAnalyser.Pause;
begin

end;

procedure TMultiThreadedWebAnalyser.Reset;
begin
 // prepare dictionary
 if ResultURLDictionary <> nil then
 begin
  ResultURLDictionary.Free;
  ResultURLDictionary := nil;
 end;
 ResultURLDictionary := TObjectDictionary<string, TURLNodeTreeData>.Create([doOwnsValues]);
 // set variables;
 FCancelled := false;
 FAnalyserStatus := asIdle;
 FMaxThreadPoolCount := 10;
 FProgressData.Added := 0;
 FProgressData.Analysed := 0;
 FProgressData.ActiveThreads := 0;
 FProgressData.Processed := 0;
end;

procedure TMultiThreadedWebAnalyser.Resume;
begin

end;

procedure TMultiThreadedWebAnalyser.Start;
var
 threadcounter: integer;
 condef: IFDStanConnectionDef;
begin
 // set analyser state
 FAnalyserStatus := asBusy;
 // set cancel flag
 FCancelled := false;
 // check if connection definition exists
 condef := FDManager.ConnectionDefs.FindConnectionDef(ConDefName);
 if not Assigned(condef) then
  condef := FDManager.ConnectionDefs.AddConnectionDef;
 condef.Name := ConDefName;
 condef.DriverID := 'SQLite';
 condef.Database := FResultDataBaseFileName;
 condef.Pooled := true;
 condef.UserName := '';
 condef.Password := '';
 condef.Params.Add('SharedCache=False');
 condef.Params.Add('LockingMode=Normal');
 condef.Params.Add('Synchronous=Full');
 condef.Params.Add('LockingMode=Normal');
 condef.Params.Add('CacheSize=60000');
 condef.Params.Add('BusyTimeOut=30000');
 condef.Params.Add('POOL_MaximumItems=' + IntToStr(FMaxThreadPoolCount + 1));
 condef.Apply;
 // set fdmanager active
 FDManager.Active := True;
 // set lenght of threadpool array
 SetLength(FURLAnalyserThreadPool,FMaxThreadPoolCount);
 // now create each thread
 for threadcounter := 0 to FMaxThreadPoolCount - 1 do
 begin
  // create thread
  FURLAnalyserThreadPool[threadcounter] := TURLAnalyser.Create;
 end;
end;

procedure TMultiThreadedWebAnalyser.Stop;
var
 threadcounter: integer;
begin
 // close connection pool
 FDManager.CloseConnectionDef(ConDefName);
 // terminate each thread
 for threadcounter := FMaxThreadPoolCount - 1 downto 0 do
 begin
  // create thread
  TURLAnalyser(FURLAnalyserThreadPool[threadcounter]).Terminate;
 end;
 // now wait for termination and free each thread
 for threadcounter := FMaxThreadPoolCount - 1 downto 0 do
 begin
  // create thread
  TURLAnalyser(FURLAnalyserThreadPool[threadcounter]).WaitFor;
  TURLAnalyser(FURLAnalyserThreadPool[threadcounter]).Free;
 end;
 // set analyser state
 FAnalyserStatus := asIdle;
end;


und hier der code des/der threads

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
{ TURLAnalyser }

procedure TURLAnalyser.Execute;
var
 oConn: TFDConnection;
begin
 FreeOnTerminate := False;
 oConn := TFDConnection.Create(nil);
 oConn.ConnectionDefName := ConDefName;
 try
  oConn.Connected := True;
  while not Terminated do
  begin


  end;
 finally
  oConn.Free;
 end;
end;
NOS1971 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 193

Windows 8.1 PRO 64 Bit
Delphi XE7 Professional
BeitragVerfasst: So 27.07.14 18:06 
Also das Threading an sich ist nun stabil .... allerdings gibt es noch ein paar probleme ...

ich habe nun in jedem thread eine connection und dazu 2 queries .... ist das ok oder darf es nur eine sein ?

ich nutze eine um das aktuelle item aus der db zu holen welches ich bearbeite ... das halte ich offen und mache eine analyse ... am ende der analyse aktualisiere ich es ... in einer procedure die aus der analyse aufgerufen wird und zum thread gehört adde ich über eine zweite wuery daten in die db

weiterhin stelle ich fest das trotz laufender threads nur einer einen gültigen datensatz zum bearbeiten aus der db holt ... als wenn der rest geblockt ist ...

any idea ?
hk
Hält's aus hier
Beiträge: 2


C, Delphi
BeitragVerfasst: So 03.08.14 16:43 
user profile iconNOS1971 hat folgendes geschrieben Zum zitierten Posting springen:

ich habe nun in jedem thread eine connection und dazu 2 queries .... ist das ok oder darf es nur eine sein ?


Hallo. Eine Connection je Thread ist richtig, siehe auch
docwiki.embarcadero....eading_%28FireDAC%29
"Die Standardvereinfachung besteht im Erstellen und Verwenden eines zugehörigen Verbindungsobjekts zur Arbeit mit der Datenbank für jeden Thread. In diesem Fall ist keine zusätzliche Serialisierung erforderlich."

Ich habe auch so meine Probleme beim ersten Umgang mit FireDAC. Zum Beispiel

ausblenden Delphi-Quelltext
1:
2:
3:
4:
if FDManager.IsConnectionDef('MSSQL_Connection'then
  FDManager.DeleteConnectionDef('MSSQL_Connection');
if FDManager.IsConnectionDef('MSSQL_Connection'then
  showmessage('immer noch vorhanden');  // => und es ist noch vorhanden!


Gruß, hk
NOS1971 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 193

Windows 8.1 PRO 64 Bit
Delphi XE7 Professional
BeitragVerfasst: So 03.08.14 17:13 
also bei mir will das einfach nicht hinhauen und ich habe wirklich keinen plan warum das mit dem pooling nicht funktioniert.

Das mit den Conectiondefinitions habe ich so gemacht

ausblenden Delphi-Quelltext
1:
2:
var
 condef: IFDStanConnectionDef;


ausblenden 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:
 // close fdmanager
 FDManager.Close;
 // check if connection definition exists
 condef := FDManager.ConnectionDefs.FindConnectionDef(ConDefName);
 if not Assigned(condef) then
  condef := FDManager.ConnectionDefs.AddConnectionDef;
 // add connection definition
 condef.Name := ConDefName;
 condef.DriverID := 'SQLite';
 condef.Database := FResultDataBaseFileName;
 condef.Pooled := true;
 condef.UserName := '';
 condef.Password := '';
 condef.Params.Add('SharedCache=False');
 condef.Params.Add('LockingMode=Normal');
 condef.Params.Add('Synchronous=Full');
 condef.Params.Add('LockingMode=Normal');
 condef.Params.Add('CacheSize=60000');
 condef.Params.Add('BusyTimeOut=30000');
 condef.Params.Add('POOL_MaximumItems=' + IntToStr(FMaxThreadPoolCount + 1));
 condef.Apply;
 // set fdmanager active
 FDManager.Active := True;


das funktioniert super ... ich habe so das gefühl das das schreiben aus einem query im thread über die connection des threads probleme macht solange das andere query einen datensatz über die gleiche connection offen hält.
hk
Hält's aus hier
Beiträge: 2


C, Delphi
BeitragVerfasst: So 03.08.14 17:24 
user profile iconNOS1971 hat folgendes geschrieben Zum zitierten Posting springen:

ich habe so das gefühl das das schreiben aus einem query im thread über die connection des threads probleme macht solange das andere query einen datensatz über die gleiche connection offen hält.


Greifen die beide Queries auf dieselbe Tabelle zu? Dann könnte es wohl Probleme geben.
Ich muss mich aber auch erst noch in FireDAC einarbeiten.
NOS1971 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 193

Windows 8.1 PRO 64 Bit
Delphi XE7 Professional
BeitragVerfasst: So 03.08.14 19:20 
Ja .... beide Queries greifen auf die selbe tabelle zu ...

es ist eine Webseitenanalysesoftware und der kern, also quasi der crawler, ist multithreaded .... so hole ich mir quasi mit der einem query des threads die nächste zu analysierende url aus der tabelle und halte den datensatz offen während die andere query die daten der gefundenen urls in die tabelle schreibt.

da habe ich auch noch keine wirklich funktionierende lösung gefunden ... auch ohne firedac lief das nicht besonders sauber ... ich dachte eigentlich es wird durch die query nur der datensatz geblockt und nicht die tabelle.