Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 24.06.2016, 19:37
drcham drcham вне форума
Прохожий
 
Регистрация: 24.06.2016
Сообщения: 2
Версия Delphi: Delphi Seattle
Репутация: 10
По умолчанию потоки ttask получение и передача параметров

Добрый день всем. Требуется распараллелить вычисление интеграла. Алгоритм сам выглядит так:
Необходимо посчитать интеграл в диапазоне [a,b] f(t)=sin(x*t)dx (на деле формула в три раза длиннее).

Поскольку интервал очень большой и из-за специфики функции его расчет возможен только по расчету суммы на каждом периоде sin. Т.е. в программе сделан цикл по каждому периоду синуса и общая сумма потом складывается. Считает все это программа довольно медленно. Поэтому решено сделать расчет с использованием потоков.

Прочитал что есть класс TTask.
Сделал:
Код:
Для теста можно функцию integrator в любом виде представить.

var
     tasks: array of ITask;
     sums:array of double;
     i:integer;
     int_period_start,int_period_end:extended;
     total:extended;
begin
   Setlength (tasks ,norm_period_count); //число периодов синуса в [a,b]
   Setlength (sums ,norm_period_count);// массив куда суммы на каждом периоде записывать
   for i := 0 to trunc(norm_period_count)-1 do //цикл по периодам
   begin
     int_period_start:=i*period; //a 
     int_period_end:=(i+1)*period; //b
     // диапазон на котором интегрировать на каждом потоке
      Tasks[i] := TTask.Create (procedure()
        begin
          //в поток выносим вычисление.
          res:=Integrator(i*period, (i+1)*period,current_time);
          //current_time - это "t" или точка времени в которой надо посчитать интеграл. 
          //TInterlocked.Exchange(sums[i],res);
          //Result:=res;
//              TThread.Synchronize(nil,
//            procedure
//            begin
//                  sums[1]:=res;
//            end);
       end);
      Tasks[i].Start; //запускаем поток

    end;

  TTask.WaitForAll(tasks); //ждем завершения
  total:=0;
 for i := 0 to High(sums) do
  begin
    total:=total+sums[i];// считает сумму и выдаем результат.
  end;
   Result:=total;

К сожалению моих знаний катастрофически не хватает.
В текущем варианте функция даже работает но в массив sums ничего не записывает. Пробовал оба варианта. Они закомментированы сейчас.

Прошу помощи как отладить данный алгоритм. Может быть надо iFuture использовать... хотя я тоже пробовал, но не смог реализовать.

Повторюсь что задача состоит в том, чтобы запустить параллельно в отдельном потоке вычисление интегрирования на заданном участке. В ответ получить значение суммы и потом просто сложить их. Количество периодов будет расти и довольно сильно т.к. sin (2*pi/t), а t это время которое считает от 1мкс до 800мкс в среднем.

Заранее спасибо. Могу поблагодарить если потребуется.

Последний раз редактировалось drcham, 24.06.2016 в 20:22.
Ответить с цитированием
  #2  
Старый 25.06.2016, 06:41
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,052
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Похоже, это что-то из нового. Для старого варианта потоков:

Поток:
Код:
TMyThread = class(TThread)
private
  function GetIntegralValue(a, b : Extended) : Double;
public
  IsDone : Boolean;
  Value : Double;
  a, b : Extended;
protected
  procedure Execute; override;
end;
...
function TMythread.GetIntegralValue(a, b : Extended) : Double;
begin
  // Твоя функция
  result := Random * Random(100);
end;

procedure TMythread.Execute;
begin
  IsDone := False;
  Value :=   GetIntegralValue(a,b);
  IsDone := True;
end;

Основной код:
Код:
var
  Result : Double;
  N : Integer;
  a, b : Extended;
  a1, b1 : Extended;
  i : Integer;
  threads : array Of TMyThread;
  f : Boolean;
begin
  // интервал
  a := ...;
  b := ...;
  // Кол-во потоков
  N := 10;
  SetLength(threads,N);

  // Создаем и запускаем потоки
  For I := 0 To N-1 Do
  begin
    threads[i] := TMyThread.Create(True);
    threads[i].a := a + I*((b-a)/N);
    threads[i].b := threads[i].a + ((b-a)/N);
    threads[i].FreeOnTerminate := False;
    threads[i].Resume;
  end;

  // Ждем пока все выполнится
  sleep(1000); // 1 сек
  repeat
    f := true;
    For I := 0 To N-1 Do
      f := f and threads[i].IsDone;
  until f;

  // все готово, собибаем результат и убиваем потоки
  Result := 0;
  For I := 0 To N-1 Do
  begin
    Result := Result + threads[i].Value;
    threads[i].Free;
  end;

Как-то так.
Вот еще для информации родной пример: http://docwiki.embarcadero.com/CodeE...epSort_(Delphi)

Можно сделать так, что потоки сами будут через синхронизацию писать результат по переданному адресу, ну и вообще код упростить. Но для общего понимания такой вариант проще.

ЗЫ. Для тех, кто святее папы римского. Я знаю, что код написан довольно грязно. Но лишние строк 20-30 только усложнят понимание сути, так что это сделано намеренно.

Последний раз редактировалось lmikle, 25.06.2016 в 19:10.
Ответить с цитированием
  #3  
Старый 26.06.2016, 20:51
drcham drcham вне форума
Прохожий
 
Регистрация: 24.06.2016
Сообщения: 2
Версия Delphi: Delphi Seattle
Репутация: 10
По умолчанию

Спасибо. Добрался до компа. Сейчас буду разбираться.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 08:23.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter