[Dlephi] TTask(並列処理(タスク処理))とTThread(非同期処理(マルチスレッド))と。 – Information Teaching Service 雄飛

[Dlephi] TTask(並列処理(タスク処理))とTThread(非同期処理(マルチスレッド))と。

こんばんは、脇保です。

ここ数日の連投です。

今回は、かなーり久しぶりに、Dlephi関連の投稿をと。

ここ暫く、タスク処理とマルチスレッドにハマっておりまして。
いや、ドツボにハマった、というわけではないんですが。

どっちがいいんだろう、どっちが、どの様な用途がベスト何だろうかと。

そこで、簡単なサンプルを書いて、試してみました。

環境は、
Windows10 64Bit
Delphi10.1 Berrin Update2、
になります。

以下のサイトを参考にしました。

embacadero 並列プログラミング ライブラリの TTask の使用 http://docwiki.embarcadero.com/RADStudio/Berlin/ja/%E4%B8%A6%E5%88%97%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0_%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE_TTask_%E3%81%AE%E4%BD%BF%E7%94%A8

edn Delphi Tips – マルチスレッドアプリケーション http://support.embarcadero.com/jp/article/35961


Delphi Tips & Tricks サブフォルダ以降も含めファイルを検索する(再帰呼び出し) http://www.geocities.jp/asumaroyuumaro/program/tips/SearchFileRecall.html

サンプル作成に当たり、エンデバガロの公式wikiとedn、
その他のDlephi関連のサイトを参考にさせていただきました。

 

作成したサンプルアプリケーション。
ファイルの再帰検索を、TTaskとTThreadで行う。
 

特徴として、面白いと感じたのは、少量のファイル検索では、
マルチスレッドの方が、かなり速かったということ。
逆に、大量のファイル検索処理では、立場は逆転し、TTaskの方が、
安定した検索時間を記録しました。
対して、マルチスレッドはというと、かなり遅かったです。

まだ、処理の内容を色々試していないので、何とも言えませんが。

マルチスレッドの方は、入れ子にして処理しているので、
記述はシンプルに書けると思います。
(デバッグの方は、、、・・・白目)

基本、マルチスレッドは、同期処理ではなく、非同期処理なので、
ぶっちゃけ、用途は限られると思います。
複数走らせた場合、同期されないので、どんな結果になるか・・・。

その面、TTaskは、同期されているので、複数走らせても、
結果を同期できるのが安心です。

以下、作り方。
(ソースのコメントが少なくてすいません汗)

Buuton2つ、Edit一つ、DriveBox一つ、DirectryList一つ、Memo一つ、ListBox一つ、
をフォームに配置します.

以上、Dlephiのスレッドネタでした。
以下全ソース。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  System.Threading,//追加。TTaskライブラリの読み込み
  Vcl.FileCtrl;

type
  //ここから
  ThreadFunc = function():boolean;
  TisThread = class(TThread)
  private
    { Private 宣言 }
  public
    func_set: ThreadFunc;
  protected
    procedure Execute; override;
  end;
  TMyFunctionArray = array[0..255] of function():boolean;
  //ここまで追加。

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    ListBox1: TListBox;
    DriveComboBox1: TDriveComboBox;
    DirectoryListBox1: TDirectoryListBox;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure DirectoryListBox1Change(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    //Privateに以下を追加。
    isThread: TisThread;
    function Run(f:TisThread):boolean;
    function RunFindDir():TisThread;
    function FindDir(Dir,FindFileType: string;files:TStringlist):string;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
  //ここから
  procedure TisThread.Execute;
  function run_method:boolean;
  function set_function(f:ThreadFunc):boolean;
    var
      s:TMyFunctionArray;
    begin
      s[0] := f;
    end;
  begin
    run_method := true;
    try
      set_function(func_set);
    except
      run_method := false;
    end;
  end;

begin
  run_method;
  if Application.Terminated then begin

  end;
end;

function Tform1.Run(f:TisThread):boolean;
begin
  try
    try
      isThread:= f;
      if isThread=nil then
        isThread:=TisThread.Create(false);
    except
      //例外が発生した場合にここに移動
    end;
  finally
    //処理が成功した場合にここに移動
  end;
  exit;
end;

function TForm1.FindDir(Dir,FindFileType: string;files:TStringlist):string;
var
  Rec: TSearchRec;
begin
  //フォルダ名の最後に がついていなければつける
  Dir :=IncludeTrailingPathDelimiter(Dir);
  if FindFirst(Dir + FindFileType, faAnyFile, Rec) = 0 then
  try
    repeat
     if Rec.Attr and faDirectory <> 0 then
      begin
          if (Rec.Name='.') or (Rec.Name='..') then
            Continue;
            //フォルダなら再度この関数を呼び出し
            Result :=FindDir(Dir + Rec.Name,FindFileType,files);
      end
      else begin //ファイルなら追加
          files.Add(Dir + Rec.Name);
          form1.Caption := Dir + Rec.Name
      end;

      Application.ProcessMessages;
    until (FindNext(Rec) <> 0) or (Result <> '');
  finally
     FindClose(Rec);
  end;
end;

function Tform1.RunFindDir():TisThread;
var
  Time: Cardinal;
  st:Tstringlist;
begin
  st := tstringlist.Create;
  st.Clear;
  Time :=GetTickCount;
  FindDir(form1.Edit1.Text,'*.*',st);
  form1.Memo1.Lines.Add('TThread処理時間: '+IntToStr(GetTickCount -Time));
  form1.Memo1.Lines.Add(edit1.Text+':'+IntToStr(st.Count)+'files');
  form1.ListBox1.Items.Text := st.Text;
  st.Free;
  showmessage('処理が完了しました。');
end;
//ここまで追加

//Button1Clickに以下を追加。
procedure TForm1.Button1Click(Sender: TObject);
var
  Time: Cardinal;
  st:Tstringlist;
  Task1: ITask;
begin
  st := tstringlist.Create;
  st.Clear;
  Task1 := TTask.Create (procedure ()
  begin
    Time :=GetTickCount;
    FindDir(form1.Edit1.Text,'*.*',st);
    form1.Memo1.Lines.Add('TTask処理時間: '+IntToStr(GetTickCount -Time));
  form1.Memo1.Lines.Add(edit1.Text+':'+IntToStr(st.Count)+'files');
    form1.ListBox1.Items.Text := st.Text;
    showmessage('処理が完了しました。');
    st.Free;
  end);
  Task1.Start;
end;

//Button2Clickに以下を追加。
procedure TForm1.Button2Click(Sender: TObject);
begin
  run(RunFindDir());
end;

//DirectoryListBox1Changeに以下を追加。
procedure TForm1.DirectoryListBox1Change(Sender: TObject);
begin
  edit1.Text := form1.DirectoryListBox1.Directory;
end;

//FormCreateに以下を追加。
procedure TForm1.FormCreate(Sender: TObject);
begin
  edit1.Text := form1.DirectoryListBox1.Directory;
end;

end.

コメントをどうぞ

メールアドレスが公開されることはありません。 が付いている欄は必須項目です