|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Снижение загрузки ЦП или увеличение скорости программы
Подскажите пожалуйста, я делаю программу, которая рассчитывает все возможные исходы одного процесса.
Процесс зависит от 20-ти переменных, диапазоны значений которых либо известны изначально, либо зависят друг от друга. Таким образом получается 20 вложенных циклов for. Расчет происходит в 4 этапа (6-6-6-2 цикла), после каждого происходит обращение к подпрограмме, в которой только блок условий if-then-else,считающий переменные для следующего этапа. При стандартном наборе переменных программа вычисляет больше миллиарда вариаций, что занимает у нее больше 12 минут. Процесс идет в 2 потока и грузит 33% ЦП, при этом программа виснет и не отвечает в диспетчере задач. Я попытался снизить количество вычислений следующим образом: вычленил некоторые закономерности процесса и, в случае наступления такой закономерности, пропускал последнее обращение к подпрограмме переходя к следующему значению по циклу. Однако время расчета не снизилось даже на секунду, то есть, как я понял, блок, содержащий только условия, ЦП практически не грузит. Есть ли способ как-то еще снять нагрузку, чтобы снизить время хотя бы до 3,5 минут? Некоторые циклы при определенных условиях содержат всего одно значение, если от них как-нибудь избавиться, то это снизит нагрузку? Последний раз редактировалось Dogmat-iGwt, 22.03.2012 в 10:21. |
#2
|
||||
|
||||
Закинь сюда проджект, посмотрим.
Помогаю платно. Помогаю иногда бесплатно. |
#3
|
|||
|
|||
Я б закинул, но он уже сейчас растянулся на 2 с лишним тысячи строк, это к нему как минимум комментарии надо писать...
|
#4
|
||||
|
||||
Без кода можешь обращаться в "Битву экстрасенсов" или программу "Люди Хэ".
Кидай 2000 строк, посмотрю по врмени выполнения. Помогаю платно. Помогаю иногда бесплатно. |
#5
|
||||
|
||||
Цитата:
Я вообще не понял: есть 20 вложенных циклов, а процесс идет в 2х потоках. Это как? |
#6
|
|||
|
|||
Код в студию. А чтобы программа "не зависала" во время вычислений вставь внутри циклов <Application.ProcessMessages>.
|
Этот пользователь сказал Спасибо icsander за это полезное сообщение: | ||
Dogmat-iGwt (24.03.2012)
|
#7
|
||||
|
||||
Цитата:
Цитата:
И оно точно в 2 потока работает? Т.е. если оно действительно многопоточное, то почему, например, не 10? Цитата:
Цитата:
Посмотри на пакеры exe, теоретически могут и ускорить работу. + Могут помочь опции компиляции. Нет повести печальнее на свете, чем повесть о заклиневшем Resete. Последний раз редактировалось Ferra, 24.03.2012 в 00:39. |
Этот пользователь сказал Спасибо Ferra за это полезное сообщение: | ||
Dogmat-iGwt (24.03.2012)
|
#8
|
||||
|
||||
Цитата:
|
#9
|
||||
|
||||
Цитата:
Но ты путаешь понятия. Например вот посмотри http://www.cyberguru.ru/programming/delphi/threads.html Если твой алгоритм можно распараллелить - то это прилично ускорит скорость работы. И необязательно циклы в разных потоках запускать. Просто выдели части алгоритма которые могут выполняться параллельно. Нет повести печальнее на свете, чем повесть о заклиневшем Resete. Последний раз редактировалось Ferra, 24.03.2012 в 00:55. |
Этот пользователь сказал Спасибо Ferra за это полезное сообщение: | ||
Dogmat-iGwt (24.03.2012)
|
#10
|
|||
|
|||
Ладно, вот приложил чуть-чуть упрощенную версию проги, рассчитывает только количество вариаций=победы+поражения+ничьи. В коде весь ступор в обработчике главной кнопки, остальное все работает нормально.
Как пользоваться: в каждой из 8-ми панелей нужно выбрать по карте, выбор производится проще всего по имени (верхний левый комбобокс на каждой из 8 панелей). Рекомендую прежде чем нажать вычислить выставить в 2-х комбобоксах с надписью 12 в правом-верхнем и правом-нижнем углах окна цифры поменьше. Уже при значении 8 в каждом из них программа считает около минуты. При 12 количество вариаций переваливает за миллиард, прога виснет надолго. Если что, не удивляйтесь некоторым моим решениям, я новичок самоучка, заранее спасибо. Советам, не относящимся к сути вопроса, тоже буду благодарен. |
#11
|
|||
|
|||
Цитата:
Это я кстати тоже не догнал почему в 2 потока, но судя по инфе из диспетчера задач, их 2. Грузят они ровно 33% ЦП. У меня трехядерный атлон. |
#12
|
||||
|
||||
Я просто думал, что ТС организовал вычисления в 2 треды Насчет 2х потоков в диспетчере, то это винда виновата - второй поток на иные вычисления (интерфейс например). Вот из-за этого и 33% - что 3х ядерный Атлон - процесс идет только на одном ядре, интерфейс не отвечает...
|
#13
|
||||
|
||||
Про логическую оптимизацию ни чего не скажу, т.к. одному автору известно что он задумал, а вот про то как все это организовано могу сказать две вещи.
1. В процедуру fight передается слишком много параметров, поэтому нужно сделать новый тип при помощи оператора record, забить все параметры в этот тип, объявить переменную этого типа, и передавать в процедуру указатель на эту переменную 2. все вычисления которые можно вычислить заранее убери за тело цикла(ов), так как при каждом шаге цикла, у тебя вычисляется одно и тоже. Например: в коде for i:=1 to 2*cos(2-3)/100/450*43 место, которое выделено нужно рассчитывать заранее, и подставлять в это место заранее вычисленное значение. Если хотя бы по этим принципам оптимизации пойдешь, получишь видимый эффект! |
Этот пользователь сказал Спасибо Pilot_Red за это полезное сообщение: | ||
Dogmat-iGwt (24.03.2012)
|
#14
|
|||
|
|||
Попробую сделать, как вы советуете. Однако возникает вопрос, почему когда я сделал так, чтобы программа перепрыгивала последний fight примерно в 35-40% случаев, то есть отсеял примерно 150 миллионов обращений к подпрограмме из 2 миллиардов, но при этом время вычисления осталось таким же?
|
#15
|
||||
|
||||
Зависит от того, как делали. Если использовали много IF-ов - то, скорее всего, просто выиграли в количестве вызовов функции fight, но проиграли в количестве действий внутри циклов (а if - относительно медленная вещь).
По поводу функции fight - да, параметров слишком много. Передача указателя на структуру по идеи ускорит работу в пару раз. Потом, некоторые блоки условий можно сгруппировать. Например: Код:
if (B1=1) and (B2i=1) then B2:=2 else if (B1=2) and (B2i=1) then B2:=1 else if (B1=3) and (B2i=1) then B2:=1 else if (B1=4) and (B2i=1) then B2:=1 Код:
if (B2i=1) then begin if (B1=1) then B2:=2 else B2:=1; end; UPD: Более того, сейчас заметил, что весь код Код:
if (B1=1) and (B2i=1) then B2:=2 else if (B1=2) and (B2i=1) then B2:=1 else if (B1=3) and (B2i=1) then B2:=1 else if (B1=4) and (B2i=1) then B2:=1 else if (B1=1) and (B2i=2) then B2:=3 else if (B1=2) and (B2i=2) then B2:=3 else if (B1=3) and (B2i=2) then B2:=2 else if (B1=4) and (B2i=2) then B2:=2 else if (B1=1) and (B2i=3) then B2:=4 else if (B1=2) and (B2i=3) then B2:=4 else if (B1=3) and (B2i=3) then B2:=4 else if (B1=4) and (B2i=3) then B2:=3; Код:
if (B1<=B2i) then B2:=B2i+1 else B2:=B2i; И еще: я, конечно, в коде не разобрался особо, но уверен, что большинство IFов можно записать в циклы или сгруппировать друг с другом (хотя бы найти взаимоисключающие IFы в функции fight и поставить else), повысив читаемость кода и, возможно, увеличив скорость. P.S. уже не по поводу оптимизации: через два месяца такие названия переменных вскроют мозг даже тому, кто этот код писал, не говоря уже о тех, кто пытается в нём разобраться. На будущее - лучше использовать более развёрнутые и осмысленные имена. jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 24.03.2012 в 14:16. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
Dogmat-iGwt (25.03.2012)
|