|
#1
|
|||
|
|||
Многопоточность
Доброго времени суток.
Попробовал написать многопоточную программу (до этого нужды не было в это лезть) и как говорится первый блин комом. Суть проблемы в следующем программа производит значительное число однотипных расчетов, по сути которые можно обсчитывать параллельно. С помощью класса TThread создается программой несколько потоков (число потоков определяется пользователь программы) каждый из которых берет на себя равную часть расчетов. Потоки формируются и отрабатывают правильно расчет (проверял) однако скорость осталась прежней, что и с одним потоком. В диспетчере задач показано, что программе присвоен один процесс и загрузка процессора всегда 25%, не зависимо от числа потоков. Что я не правильно понял? |
#2
|
||||
|
||||
Кусок кода сказал бы больше, чем 80% вашего сообщения
Оставайтесь хорошими людьми... VK id2634397, ds [at] phoenix [dot] dj |
#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. Ну и число потоков лучше рассчитывать из числа процессоров/ядер, а не из объёма работ. Оставайтесь хорошими людьми... VK id2634397, ds [at] phoenix [dot] dj Последний раз редактировалось 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 поток по завершении самоуничтожается, а ты после этого его флаги читаешь. Не гут. Цитата:
jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 17.12.2013 в 21:14. |
#6
|
|||
|
|||
Цитата:
Шутку оценил Код:
ther.resume |
#7
|
|||
|
|||
Вы правы Ваш код изящней!!!
Цитата:
Но главный вопрос при этом коде ни скорость счета ни загрузка процессора не зависит от числа потоков. Процессор всегда загружен на 25% (похоже на одно ядро)!!! Почему?????? |
#8
|
||||
|
||||
Цитата:
Цитата:
Цитата:
ЗЫЖ черт, совсем забыл, что в делфе нет do-while... Надо поменять на repeat-until и условие поставить обратное. jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось 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
|
||||
|
||||
Цитата:
|