четверг, 27 февраля 2020 г.

OTL на заметку: параллельное выполнение функции в потоках, каждый со своими параметрами

Сама идея:

Запустит несколько паралельных потоков для выполнения некой общей задачи, причем каждый поток должен получить свои параметры для работы. 
Применение на будущее: например одновременно сканирование файлов в нескольких директориях, понятно что имя директории для сканирования для каждого потока должно быть свое. Хоть и алгоритм сканирования общий. 
Демо: передача параметров через блокирующую коллекцию, использование параметров через record (обертка), передаются два параметра частота и длительность, функция выполняющаяся в потоке получает эти параметры и 10 раз проигрывает сигнал с такой частотой и длительностью.
Потоков на запуск 4, работают одновременно 2....
unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  OTLParallel, OtlTaskControl, OtlCollections, OtlCommon;

type
  TParametersForProc = record
                        Hz : Integer;
                        Duration : Integer;
                       end;

  TForm3 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    Join : IOmniParallelJoin;
    CollectionParams : IOmniBlockingCollection;
  public
    { Public declarations }
    procedure JoinProcExecute;
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure Go(Hz, Duration : Integer);
var
  I: Integer;
begin
 for I := 0 to 10 do
 begin
     Sleep(1000);
     Winapi.Windows.Beep(Hz, Duration);
 end
end;

procedure TForm3.JoinProcExecute;
var
 Value     : TOmniValue;
 ParamProc : TParametersForProc;
begin
 // Взять из коллекции параметры
 CollectionParams.Take(Value);
 // Преобразовать обратно
 ParamProc := Value.Unwrap;
 // Запустить процедуру с переданными  параметрами
 Go(ParamProc.Hz, ParamProc.Duration);
 // вывести параметры
 Memo1.Lines.Add(Format('Hz : %d; duration: %d',[ParamProc.Hz, ParamProc.Duration]));
end;

procedure TForm3.Button1Click(Sender: TObject);
var
 arrayProc : array of TProc;
 I: Integer;
 Value : TOmniValue;
 ParamProc : TParametersForProc;
begin
 CollectionParams := TOmniBlockingCollection.Create;
 SetLength(arrayProc, 4);
 for I := Low(arrayProc) to High(arrayProc) do
 begin
     // Для каждого потока свои параметры, поэтому перед запуском потоков
     // в коллекцию добавляем параметры, функция выполняющаяся в потоке будет
     // брать параметр для себя из коллекции
     ParamProc.Hz       := (I+1) * 1000;
     ParamProc.Duration := (I+1) * 20;
     // обернуть рекорд к TOmniValue
     Value := TOmniValue.Wrap(ParamProc);
     // Добавим в параметры
     CollectionParams.Add(Value);
     arrayProc[i] := JoinProcExecute;
 end;
 CollectionParams.CompleteAdding;       // добавление завершено
 // NumTasks(2) - два потока выполняются одновременно
 Join := Parallel.Join(arrayProc).NumTasks(2).NoWait.Execute; // запуск параллельных потоков
end;

end.

1 комментарий:

  1. Дмитрий, у меня есть к Вам несколько вопросов по OTL, как с Вами связаться? Василий rum @ craocrimea.ru

    ОтветитьУдалить