02. marts 2008 - 22:53 Der er 6 kommentarer og
1 løsning

Hvordan undgår jag at mit program går i 'svarer ikke'?

Jeg har en rutine den gennemsøger alle poster i en database, (Fritekst søgning).
Databasen har cirka 150.000 records og de fleste af gangene går programmet i 'svarer ikke mode'. Programmet søger dog videre, og når alle records er gennemløbet vises resultatet og programmet svarer igen.
Hvordag undgår man at programmet går i 'svarer ikke'?
Jeg har forsøgt med tråde, men det blev søgningen da umanerlig langsom af.

procedure TForm36.Find;
begin
  List.Clear;
  begin
    Global.TTitel.IndexName := '';
    with Global.Titel.DataSet do
    begin
      Refresh;
      First;
      while not (EOF) do
      begin
        Led;
        Next;
      end;
    end;
  end;
end;

procedure TForm36.Led;
begin
  with Global.Titel.DataSet do
  begin
    Refresh;
    if (FieldByName('Plade').AsInteger <> 0)
      and FieldByName('Aktiv').AsBoolean then
    begin
      if (not SkalVaerePaaPc) or (FieldByName('PåHdd').AsBoolean) then
      begin
        if Pos(AnsiUpperCase(Titel.Text),
          AnsiUpperCase(FieldByName('Titel').AsString)) > 0 then Ind;
        if Pos(AnsiUpperCase(Titel.Text),
          AnsiUpperCase(FieldByName('Alternativ').AsString)) > 0 then Ind;
        if Pos(AnsiUpperCase(Titel.Text),
          AnsiUpperCase(FieldByName('Original').AsString)) > 0 then Ind;
      end;
    end;
  end;
end;

procedure TForm36.Ind;
begin
  Global.Plade.DataSet.Refresh;
  Global.TPlade.IndexName := '';
  Global.TPlade.FindNearest(
    [IntToStr(Global.Titel.DataSet.FieldByName('Plade').AsInteger)]);
  Tmp := Global.Using(Global.Plade.DataSet.FieldByName('Nummer').AsInteger);
  while Length(Tmp) < 10 do Tmp := ' ' + Tmp;
  Tmp := Tmp + Global.Titel.DataSet.FieldByName('Titel').AsString + ' ';
  while Length(Tmp) < 46 do Tmp := Tmp + ' ';
  Tmp := Tmp + Global.Titel.DataSet.FieldByName('Kunstner').AsString + ' ';
  while Length(Tmp) < 82 do Tmp := Tmp + ' ';
  Tmp := Tmp + Global.Plade.DataSet.FieldByName('Medie').AsString + '    ';
  if Global.Titel.DataSet.FieldByName('PåHdd').AsBoolean then Tmp[86] := '*';
  Tmp := Tmp + IntToStr(Global.Titel.DataSet.FieldByName('Index').AsInteger);
  List.Items.Add(Tmp);
  Fundne.Clear;
  Fundne.Items.Add(IntToStr(List.Items.Count));
  Form36.Update; // Denne linie var et forsøg på om det kunne afhjælpe fejlen.
end;
02. marts 2008 - 22:54 #1
Hvordan undgår JEG at mit program går i 'svarer ikke'?
02. marts 2008 - 23:05 #2
Routinen 'Find' gennemløber databasen en record ad gangen.
Det er routinen 'Find' der tager for lang tid.
Routinen 'Led' laver fritekst søgning på tre poster i den aktueller record, og hvis et match er fundet kaldes routinen 'Ind', til at formatere linien til ListBoksen.
Avatar billede hrc Mester
02. marts 2008 - 23:29 #3
Jeg tror nedenstående vil fikse det. Hvis du gerne vil have skærmen opdateret lidt mere kan du sætte antallet af processMessages op ved at sætte 100 ned til eksempelvis 50.

procedure TForm36.Find;
var
  i: integer;
begin
  i := 0;
  List.Clear;
  begin
    Global.TTitel.IndexName := '';
    with Global.Titel.DataSet do
    begin
      Refresh;
      First;
      while not (EOF) do
      begin
        i := i + 1;
        if (i mod 100) = 0 then
          Application.ProcessMessages;
        Led;
        Next;
      end;
    end;
  end;
end;
Avatar billede hrc Mester
02. marts 2008 - 23:37 #4
Linjerne ...

  i := i + 1;
  if (i mod 100) = 0 then // For hvert 100 gennemløb
    Application.ProcessMessages;

... burde flyttes under Led

Et alternativ til at tælle records er at lave timeouts:

procedure TForm36.Find;
var
  TickStart: cardinal;
begin
  List.Clear;
  begin
    Global.TTitel.IndexName := '';
    with Global.Titel.DataSet do
    begin
      Refresh;
      First;
      TickStart := GetTickCount;
      while not EOF do
      begin
        Led;
        if (GetTickCount - TickStart) >= 1000 then // For hvert sekund
        begin
          Application.ProcessMessages;
          TickStart := GetTickCount;
        end;
        Next;
      end;
    end;
  end;
end;

Endelig kan du måske, men her er det vist en dum idé, bruge Application.HandleMessage.
09. marts 2008 - 20:30 #5
Hej hrc
Det ser ud til at virke, jeg kan ikke længere få den til at gå i 'svarer ikke'.
Læg et svar så du kan få dine point.
Avatar billede hrc Mester
09. marts 2008 - 22:14 #6
Hvilken af løsningerne brugte du?
17. marts 2008 - 21:26 #7
Jeg kaldte Application.ProcessMessages; hver gang et hit blev fyldt i Listbox.
Jeg ved godt at den ikke er konsekvent, det er mulig at jeg laver det om lidt senere. Jeg hælder mest til den der trigger en gang i sekundet.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester