![]() |
|
|
#1
|
|||
|
|||
|
Доброго времени суток.
Попробовал написать многопоточную программу (до этого нужды не было в это лезть) и как говорится первый блин комом. Суть проблемы в следующем программа производит значительное число однотипных расчетов, по сути которые можно обсчитывать параллельно. С помощью класса TThread создается программой несколько потоков (число потоков определяется пользователь программы) каждый из которых берет на себя равную часть расчетов. Потоки формируются и отрабатывают правильно расчет (проверял) однако скорость осталась прежней, что и с одним потоком. В диспетчере задач показано, что программе присвоен один процесс и загрузка процессора всегда 25%, не зависимо от числа потоков. Что я не правильно понял? |
|
#2
|
||||
|
||||
|
Кусок кода сказал бы больше, чем 80% вашего сообщения
![]() |
|
#3
|
|||
|
|||
|
Цитата:
Код:
itc:=sedt.Value;// Определяет число параллельный потоков setlength(ther,itc); for it := 1 to itc do begin ther[it-1]:= Rasch.Create(true); //Rasch - мой класс TThread ther[it-1].FreeOnTerminate := true; if it =1 then ther[it-1].kss:=0 else ther[it-1].kss:=(it-1)*(kg mod itc)+1;// определяет с какого элемента считать начать текущему потоку if it=itc then ther[it-1].ke:=kg else ther[it-1].ke:=(it)*(kg mod itc); // определяет каким элементом закончить счет текущему потоку ther[it-1].proc:=rasc1; // определяет процедуру для расчета ther[it-1].start; end; enp:=false; while (enp=false) do //Ожидание окончание всех потоков begin enp:=ther[0].Finished; if itc>1 then for it := 2 to itc do enp:=(enp and ther[it-1].Finished); end; Чтобы было понятнее приложу код класса Rasch Код:
unit Rasc;
interface
uses
System.Classes;
type
ProcRasc = procedure(kstr, kend:integer);
Rasch = class(TThread)
private
{ Private declarations }
public
proc: ProcRasc;
kss,ke: integer;
protected
procedure Execute; override;
end;
implementation
{ Rasch }
procedure Rasch.Execute;
begin
proc(kss,ke);
end;
end.Последний раз редактировалось mustimur, 17.12.2013 в 20:38. |
|
#4
|
||||
|
||||
|
Код:
ther[it-1].start; Код:
ther[it-1].resume; P.S. А, ну и процедуры расчёта должны быть, как говорится, ThreadSafe - думаю, это объяснять не надо? P.P.S. Цитата:
![]() P.P.P.S. Ну и число потоков лучше рассчитывать из числа процессоров/ядер, а не из объёма работ. Последний раз редактировалось PhoeniX, 17.12.2013 в 20:45. |
|
#5
|
||||
|
||||
|
Небольшое дополнение.
Код:
while (enp=false) do //Ожидание окончание всех потоков begin enp:=ther[0].Finished; if itc>1 then for it := 2 to itc do enp:=(enp and ther[it-1].Finished); end; Код:
do
enp = true;
for it := 0 to itc - 1 do
enp := enp and ther[it].Finished;
while (enp = false)Код:
ther[it-1].kss:=(it-1)*(kg mod itc); ther[it-1].ke:=(it)*(kg mod itc) - 1; Код:
for it := 0 to itc-1 do begin ther[it]:= Rasch.Create(true); ther[it].FreeOnTerminate := true; ther[it].kss:=it*(kg mod itc); ther[it].ke:=(it + 1)*(kg mod itc) - 1; ther[it].proc:=rasc1; ther[it].start; end; ЗЫЖ если я правильно помню, при выставленном FreeOnTerminate поток по завершении самоуничтожается, а ты после этого его флаги читаешь. Не гут. Цитата:
Последний раз редактировалось Bargest, 17.12.2013 в 21:14. |
|
#6
|
|||
|
|||
|
Цитата:
Шутку оценил ![]() Код:
ther.resume |
|
#7
|
|||
|
|||
|
Вы правы Ваш код изящней!!!
Цитата:
Но главный вопрос при этом коде ни скорость счета ни загрузка процессора не зависит от числа потоков. Процессор всегда загружен на 25% (похоже на одно ядро)!!! Почему?????? |
|
#8
|
||||
|
||||
|
Цитата:
Цитата:
Цитата:
ЗЫЖ черт, совсем забыл, что в делфе нет do-while... Надо поменять на repeat-until и условие поставить обратное.Последний раз редактировалось Bargest, 17.12.2013 в 22:32. |
| Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
mustimur (18.12.2013)
| ||
|
#9
|
||||
|
||||
|
Чтобы цикл ожидания потоков не напрягал процессор почём зря, нужно в этом цикле сделать небольшую задержку:
Код:
repeat
Sleep(100); // Теоретически достаточно даже Sleep(0)
enp := True;
for it := 0 to itc - 1 do
enp := enp and ther[it].Finished;
until enp;И да, при "FreeOnTerminate:=True" неправомерно выполнять обращения к объекту этого потока из другого потока, так как объект к этому времени уже может быть разрушен (вследствие завершения выполнения потока). Если необходимо обращаться к объекту потока из другого потока нужно делать "FreeOnTerminate:=False", но тогда и самостоятельно разрушать объекты потоков (или возложить эту миссию на объект класса TObjectList из модуля Contnrs). Если же делать "FreeOnTerminate:=True", то так как к такому объекту потока, нельзя обращаться из другого потока - поток должен сам как-то оповестить о своём завершении. Например можно объявить глобальную переменную-счётчик потоков. При создании нового потока увеличивать эту переменную, а каждый поток перед своим завершением должен уменьшать эту переменную (обязательно через Synchronize или InterlockedDecrement), тогда в цикле достаточно просто проверять не достигло ли значение этой переменной нуля: Код:
var
NumThr: Integer = 0; // Это будет счётчик запущенных потоков
.....
begin
.....
for it := 1 to itc do
begin
ther[it-1] := Rasch.Create(True);
Inc(NumThr); // Увеличиваем количество созданных потоков на единицу
ther[it-1].FreeOnTerminate := True; // Авторазрушаемый объект потока
.....
ther[it-1].Resume;
end;
while NumThr > 0 do Sleep(100); // Ожидаем завершения всех потоков
.....
end;
.....
.....
procedure Rasch.Execute;
begin
proc(kss, ke);
InterlockedDecrement(NumThr); // Перед завершением потока уменьшаем количество
// запущенных потоков, а объект потока сам разрушится
// благодаря FreeOnTerminate := True
end; |
| Этот пользователь сказал Спасибо poli-smen за это полезное сообщение: | ||
mustimur (18.12.2013)
| ||
|
#10
|
|||
|
|||
|
Цитата:
Спасибо Вы как всегда правы ![]() |
|
#11
|
|||
|
|||
|
Цитата:
Понял я это, хотя как до жирафа доходит (должен был с самого начала сам понять), вот что значит за серьезные вещи начинать в конце дня))) Однако в свое оправдание приведу цитату из официального хелпа (он меня и направил на ложный путь порока: обращения к мертвым потокам): Цитата:
Т.е. оно True когда поток закончен или уничтожен..... Или я поть не правильно что-то понял? ![]() |
|
#12
|
||||
|
||||
|
Цитата:
|