Delphi the correct use of tasks

SITUATION

To better understand PPL and how it works Task, I tried to make a very light program in which, after clicking a button, it is ListBoxfilled with a list of directories on the disk.

procedure TForm3.Button1Click(Sender: TObject);
var proc: ITask;
begin

 //Show that something is going to happen
 Button1.Caption := 'Process...';

 proc := TTask.Create(

  procedure
  var strPath: string;
      sl: TStringDynArray;
  begin

   if (DirectoryExists('C:\Users\albertoWinVM\Documents\uni\maths')) then
    begin
     ListBox1.Items.Clear;
     sl := TDirectory.GetDirectories('C:\Users\albertoWinVM\Documents\uni\maths',
     TSearchOption.soAllDirectories, nil);

     for strPath in sl do
      begin
       ListBox1.Items.Add(strPath);
      end;

     //At the end of the task, I restore the original caption of the button 
     Button1.Caption := 'Go';
     Label1.Caption := 'Finished';

    end;
  end

 );

 proc.Start;

end;

The folder mathsthat you see above is not very large, and the task takes about 3 seconds. The task is declared as follows:

type
  TForm3 = class(TForm)
    ListBox1: TListBox;
    //... other published things var ...
  private
    proc: ITask;
  public
    //... public var ...
  end;

PROBLEM

When I work (for example) with C:\Users\albertoWinVM\Documents, I have a very large number of folders, and the program takes up to 3 minutes before filling out the ListBox.

If I closed the program (while the task is still running), having only the code above, from what I understood as reading on the Internet, the task will be executed until it finishes. Am I right?

procedure TForm3.FormDestroy(Sender: TObject);
begin
 proc.Cancel;
end;

, . ?

+4
2

TTask . , . .

proc. proc, TForm3, proc, Button1Click(). , .

, Cancel() TTask. , , ( TDirectory.GetDirectories() - - ).

TDirectory.GetDirectories() , , , , FindFirst()/FindNext() , .

, - :

type
  TForm3 = class(TForm)
    ListBox1: TListBox;
    //...
  private
    proc: ITask;
    procedure AddToListBox(batch: TStringDynArray);
    procedure TaskFinished;
  public
    //...
  end;

procedure TForm3.Button1Click(Sender: TObject);
begin
  if Assigned(proc) then
  begin
    ShowMessage('Task is already running');
    Exit;
  end;

  //Show that something is going to happen
  Button1.Caption := 'Process...';

  proc := TTask.Create(
    procedure
    var
      strFolder: string;
      sr: TSearchRec;
      batch: TStringDynArray;
      numInBatch: Integer;
    begin
      try
        strFolder := 'C:\Users\albertoWinVM\Documents\uni\maths\';
        if FindFirst(strFolder + '*.*', faAnyFile, sr) = 0 then
        try
          TThread.Queue(nil, ListBox1.Items.Clear);
          batch := nil;

          repeat
            Form3.proc.CheckCanceled;

            if (sr.Attr and faDirectory) <> 0 then
            begin
              if (sr.Name <> '.') and (sr.Name <> '..') then
              begin
                if not Assigned(batch) then
                begin
                  SetLength(batch, 25);
                  numInBatch := 0;
                end;

                batch[numInBatch] := strFolder + sr.Name;
                Inc(numInBatch);

                if numInBatch = Length(batch) then
                begin
                  TThread.Queue(nil,
                    procedure
                    begin
                      AddToListBox(batch);
                    end
                  end);

                  batch := nil;
                  numInBatch := 0;
                end;
              end;
            end;
          until FindNext(sr) <> 0;
        finally
          FindClose(sr);
        end;

        if numInBatch > 0 then
        begin
          SetLength(batch, numInBatch)
          TThread.Queue(nil,
            procedure
            begin
              AddToListBox(batch);
            end
          end);
        end;
      finally
        TThread.Queue(nil, TaskFinished);
      end;
    end
  );
  proc.Start;
end;

procedure AddToListBox(batch: TStringDynArray);
begin
  ListBox1.Items.AddStrings(batch);
end;

procedure TForm3.TaskFinished;
begin
  proc := nil;
  Button1.Caption := 'Go';
  Label1.Caption := 'Finished';
end;

procedure TForm3.FormDestroy(Sender: TObject);
begin
  if Assigned(proc) then
  begin
    proc.Cancel;
    repeat
      if not proc.Wait(1000) then
        CheckSynchronize;
    until proc = nil;
  end;
end;
+7

, . . (.. ) , , .

- , , , , :

procedure TForm1.UpdateDirectoryList(AList : TStringDynArray);
var
  strPath : string;
begin
  ListBox1.Items.BeginUpdate;
    ListBox1.Items.Clear;
    for strPath in AList do ListBox1.Items.Add(strPath);
  ListBox1.Items.EndUpdate;      
  Button1.Caption := 'Go';
  Label1.Caption := 'Finished';
end;

, :

procedure TForm1.Button1Click(Sender: TObject);
var proc: ITask;
begin
  Button1.Caption := 'Process...';
  ListBox1.Items.Clear;
  proc := TTask.Create(
    procedure
    var
      sl: TStringDynArray;
    begin
      if (DirectoryExists('C:\Users\albertoWinVM\Documents\uni\maths')) then
        begin
          sl := TDirectory.GetDirectories('C:\Users\albertoWinVM\Documents\uni\maths',
                                      TSearchOption.soAllDirectories, nil);
          TThread.Queue(nil, procedure
                             begin
                               UpdateDirectoryList(sl);
                             end);
        end;
    end);
  proc.Start;
end;

, , , - .

ITask.Cancel - . .CheckCanceled, , . CheckCanceled EOperationCancelled, , . , @Remy, , .

+1

Source: https://habr.com/ru/post/1655091/


All Articles