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

Delphi Sources



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

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 09.07.2013, 01:37
cadavar cadavar вне форума
Прохожий
 
Регистрация: 09.07.2013
Сообщения: 5
Версия Delphi: xe5
Репутация: 10
Вопрос Распараллеливание задачи

О задаче:

имеется функция состоящая из 4 блоков:

блок 1

вычисляются элементы (с первого по N) для одномерного массива, по некой формуле

блок 2

вычисляются элементы (с N+1 по N+M) по другой формуле

блок 3

вычисляются элементы (с N+M+1 по N+M+K) по третьей формуле

блок 4
результат функции который вычислит сумму всех элементов (от 1 до N+M+K) для массива


_____________

Сама задача решена и программа работает правильно, однако это очень длительный (многочасовой) процесс. Мне хотелось сократить время выполения задачи, так как блоки 1, 2 и 3 абсолютно паралелльны и никак не зависят друг от друга. И только четвертый блок, т.е. сам результ зависит от них. Эта программа грузит только одно ядро. Хочется разбросать задачу на три ядра или треда.


_____________

Вопрос: Как сделать так, чтобы блоки 1, 2 и 3 в этой функции прогонялись паралелльно (грузя 3 ядра, а не одно), и чтобы четвертый блок дождавшись их выполнил преобразования и выдал необходимый результат.


Я никогда не работал с мульти-тредингом, область для меня совсем новая. Поэтому пожалуйста объясните подробно как разрешить данную проблему. Если нужно я приведу сам пример. Или выберите подходящий пример на Ваше усмотрение. Мне главное понять суть распараллеливания.

Читал хелпы мануалы и прочее. Везде про треды рассказывается довольно мутно и непонятно на каких-то нудных примерах.



Спасибо.
Ответить с цитированием
  #2  
Старый 09.07.2013, 02:37
Аватар для orion_asm
orion_asm orion_asm вне форума
Прохожий
 
Регистрация: 23.06.2012
Адрес: Украина, Днепропетровск
Сообщения: 19
Версия Delphi: XE3
Репутация: 10
По умолчанию

Если функция выполняет вычисления с данными в массиве, при этом сам массив не изменяется, думаю, логично создать 3 отдельных процесса, каждый из которых будет выполнять свои действия независимо друг от друга. Выделить место для хранения результатов каждого процесса, а массив для всех один, и из него производится лишь чтение.
Ответить с цитированием
  #3  
Старый 09.07.2013, 02:57
cadavar cadavar вне форума
Прохожий
 
Регистрация: 09.07.2013
Сообщения: 5
Версия Delphi: xe5
Репутация: 10
По умолчанию

Цитата:
Сообщение от orion_asm
при этом сам массив не изменяется,
Меняется массив во всех блоках, просто элементы не зависят друг от друга.

вот грубый пример:

Код:
function deystvie(a,b:real):real;
const n=1000; m=1200; k=189; 
var i:integer; d:array[1..n+m+k] of real; c:real;
begin

{block 1}
for i:=1 to n do
d[i]:=exp(0.2*i)*36598/sin(pi*i)+a;

{block 2}
for i:=n+1 to n+m do
d[i]:=cos(pi*i)*exp(2*i)-b;

{block 3}
for i:=n+m+1 to n+m+k do
d[i]:=1987456*i-3243555*sqrt(i)*sqr(a*b);

c:=0;
for i:=1 to n+m+k do
c:=c+d[i]

Result:=c 


end;



Цитата:
думаю, логично создать 3 отдельных процесса, каждый из которых будет выполнять свои действия независимо друг от друга.
Расскажите как сделать чтобы три процесса работали одновременно? Спасибо
Ответить с цитированием
  #4  
Старый 09.07.2013, 06:31
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,048
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

На самом деле даже последний, четвертый, блок вполне параллелится (ну если действительно надо просто посчитать сумму элементов). Тебе надо сделать 3 потока, каждый из которых вычислит свои элементы и проссумирует их. После окончания работы он, соответственно, просигналит основному потоку о завершении. Основной поток возьмет 3 числа, сложит их и выдаст конечный результат.

Примерно так:
Код:
type
  // Базовый класс для тредов
  TCalcThread = class(TThread)
  private
    FIsDone : Boolean;
    FFrom, FTo : Integer;
    FSum : Integer;
  ...
  public
    constructor Create(AFrom, ATo : Integer); virtual;
    property IsDone : Boolean read FIsDone;
    property Sum : Integer read FSum;
 end;

constructor TCalcThread.Create(AFrom, ATo : Integer);
begin
  inherited Create(False);
  FFrom := AFrom;
  FTo := ATo;
  FIsDone := False;
  FSum := 0;
end;
Далее создаешь 3 треда (T1st, T2nd, T3rd), где в перекрытом методе Execute делаешь все вычисления. В конце присваиваешь значение суммы в поле FSum, а в поле FIsDone присваиваешь True.
Код главного потока:
Код:
var
  t1, t2, t3 : TCalcThread;
  S : Integer;
begin
  t1 := T1st.Create(1, N);
  t2 := T2nd.Create(N+1,N+M);
  t3 := T3rd.Create(N+M+1,N+M+K);
  While True Do
    Begin
      If t1.IsDone And t2.IsDone And t3.IsDone Then
        Begin
           S := t1.Sum + t2.Sum + t3.Sum;
           FreeAndNil(t1);
           FreeAndNil(t2);
           FreeAndNil(t3);
        End;
      Sleep(200);
    End;
  WriteLn('S=',S); // Вывод результата
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
cadavar (09.07.2013)
  #5  
Старый 09.07.2013, 13:39
cadavar cadavar вне форума
Прохожий
 
Регистрация: 09.07.2013
Сообщения: 5
Версия Delphi: xe5
Репутация: 10
Стрелка

Спасибо за Ваши объяснения lmikle, однако многое осталось мне непонятным.

Цитата:
Сообщение от lmikle
Тебе надо сделать 3 потока, каждый из которых вычислит свои элементы и проссумирует их. После окончания работы он, соответственно, просигналит основному потоку о завершении.

Это я понял, но как это сделать. Возможно это сделать внутри одной функции? Мне нужны все полученные элементы массива, чтобы потом произвести над ними необходимые операции в 4-м блоке (и не только сумму, но три блока все равно должны остаться независимыми).


Цитата:
Далее создаешь 3 треда (T1st, T2nd, T3rd), где в перекрытом методе Execute делаешь все вычисления.

Можете рассказать как это сделать? Я слышал про Execute и Override, но с чем их едят? И как запустить три треда внутри одной функции? И что такое Sleep и FreeAndNil() (я думаю что это освобождение потока).
Могли бы показать на простейшем и понятном мне примере? Спасибо Вам еще раз.

Последний раз редактировалось cadavar, 09.07.2013 в 13:42.
Ответить с цитированием
  #6  
Старый 09.07.2013, 14:18
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

В коде lmikle все подробно описано. Создается 3 потока, каждому указывается стартовый индекс массива и конечный. Каждый из потоков должен выполнить операции над своим блоком, потом просуммировать и поставить флаг "закончил". Основной поток в цикле ждет установки всех трех флагов "закончил". Что такое Sleep и FreeAndNil можно было догадаться по смыслу или посмотреть в гугле. Sleep чтобы не тратить время на главный поток, он будет работать только раз в 200 мс. Про Execute тоже можно было без проблем почитать в гугле - примеров море, и сотый раз перепечатывать сюда 5-страничные трактаты на тему Execute нет смысла.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #7  
Старый 09.07.2013, 14:46
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

> - примеров море, и сотый раз перепечатывать сюда 5-страничные трактаты на тему Execute нет смысла.
Единственное, что не нужно желать - весь код Execute засовывать в Synchronize. Таких примеров в сети тоже полно
Ответить с цитированием
  #8  
Старый 09.07.2013, 16:07
cadavar cadavar вне форума
Прохожий
 
Регистрация: 09.07.2013
Сообщения: 5
Версия Delphi: xe5
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
В коде lmikle все подробно описано. Создается 3 потока, каждому указывается стартовый индекс массива и конечный. Каждый из потоков должен выполнить операции над своим блоком, потом просуммировать и поставить флаг "закончил". Основной поток в цикле ждет установки всех трех флагов "закончил". Что такое Sleep и FreeAndNil можно было догадаться по смыслу или посмотреть в гугле. Sleep чтобы не тратить время на главный поток, он будет работать только раз в 200 мс. Про Execute тоже можно было без проблем почитать в гугле - примеров море, и сотый раз перепечатывать сюда 5-страничные трактаты на тему Execute нет смысла.

Зачем перепечатывать? Я поэтому и попросил на простом примере, а не копипасту. И при чем тут гугл, зачем тогда нужны форумы если в них говорят "читай хелпы" или "гуглируй".
Ответить с цитированием
  #9  
Старый 09.07.2013, 16:12
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Свободен.
Цитата:
Зачем он мне?
А для того, что бы облегчить жизнь и себе, и всем остальным. Задавая в сотый раз вопрос вида "как создать новую форму" или "как создать иконку в трее", Вы не только теряете время (ждёте ответа, вместо того что б зайти в гугл и ввести два-три слова), но и тратите наше время на то, что б мы описали всё детально. А для этого мы, обычно, используем тот самый гугл

Зачем мне париться, если вы можете подсказать?
Если Вы, уважаемые, зададите (прямым текстом, или намёком) этот вопрос в своей теме (после того, как вам намекнут, что по вашему вопросу уже есть ответ в гугле) - то в дальнейшем ответ Вы вряд ли получите. Программист в первую очередь должен хотеть быть программистом. А если этого желания нет, зачем Вы тогда этим занимаетесь?
Не понимаю я людей, которые считают, что на форумах люди должны заниматься перепечатыванием документации и примеров под конкретного человека, чтобы ему было понятнее. Форумы чтобы подсказать принцип решения задачи, что уже и сделали.
Невозможно научиться программировать, если клянчить готовые решения и не прикладывать усилий к поиску информации. Например, найти информацию о работе загрузчиков ОС или каких-нибудь устройствах часто можно в единственном экземпляре в виде официальной документации. Без всяких примеров и разжевываний. На этот же вопрос информации можно накопать тонну. Если вы не хотите учиться делать что-то сам - у меня (и у многих других) нет желания вам помогать.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 09.07.2013 в 16:24.
Ответить с цитированием
  #10  
Старый 09.07.2013, 17:20
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

Ну чтобы начать


Menu->New->Other... ->[Здесь может быть меню Delphi Project->Delphi Files]Thread Object

Получишь заготовку модуля.
Затем внимательно читаешь, что здесь еще тебе насоветовали, и правишь метод Execute.
Ответить с цитированием
Этот пользователь сказал Спасибо icWasya за это полезное сообщение:
cadavar (09.07.2013)
Ответ


Delphi Sources

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

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

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

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


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


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

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

ВКонтакте   Facebook   Twitter