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

Delphi Sources



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

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 22.03.2012, 10:18
Dogmat-iGwt Dogmat-iGwt вне форума
Прохожий
 
Регистрация: 22.03.2012
Сообщения: 7
Репутация: 10
По умолчанию Снижение загрузки ЦП или увеличение скорости программы

Подскажите пожалуйста, я делаю программу, которая рассчитывает все возможные исходы одного процесса.

Процесс зависит от 20-ти переменных, диапазоны значений которых либо известны изначально, либо зависят друг от друга. Таким образом получается 20 вложенных циклов for.

Расчет происходит в 4 этапа (6-6-6-2 цикла), после каждого происходит обращение к подпрограмме, в которой только блок условий if-then-else,считающий переменные для следующего этапа.

При стандартном наборе переменных программа вычисляет больше миллиарда вариаций, что занимает у нее больше 12 минут. Процесс идет в 2 потока и грузит 33% ЦП, при этом программа виснет и не отвечает в диспетчере задач.

Я попытался снизить количество вычислений следующим образом: вычленил некоторые закономерности процесса и, в случае наступления такой закономерности, пропускал последнее обращение к подпрограмме переходя к следующему значению по циклу. Однако время расчета не снизилось даже на секунду, то есть, как я понял, блок, содержащий только условия, ЦП практически не грузит. Есть ли способ как-то еще снять нагрузку, чтобы снизить время хотя бы до 3,5 минут? Некоторые циклы при определенных условиях содержат всего одно значение, если от них как-нибудь избавиться, то это снизит нагрузку?

Последний раз редактировалось Dogmat-iGwt, 22.03.2012 в 10:21.
Ответить с цитированием
  #2  
Старый 22.03.2012, 23:01
Аватар для @Rafa3L
@Rafa3L @Rafa3L вне форума
Начинающий
 
Регистрация: 09.11.2011
Адрес: Москва
Сообщения: 144
Версия Delphi: XE2
Репутация: 11216
По умолчанию

Закинь сюда проджект, посмотрим.
__________________
Помогаю платно.
Помогаю иногда бесплатно.
Ответить с цитированием
  #3  
Старый 23.03.2012, 18:36
Dogmat-iGwt Dogmat-iGwt вне форума
Прохожий
 
Регистрация: 22.03.2012
Сообщения: 7
Репутация: 10
По умолчанию

Я б закинул, но он уже сейчас растянулся на 2 с лишним тысячи строк, это к нему как минимум комментарии надо писать...
Ответить с цитированием
  #4  
Старый 23.03.2012, 19:37
Аватар для @Rafa3L
@Rafa3L @Rafa3L вне форума
Начинающий
 
Регистрация: 09.11.2011
Адрес: Москва
Сообщения: 144
Версия Delphi: XE2
Репутация: 11216
По умолчанию

Без кода можешь обращаться в "Битву экстрасенсов" или программу "Люди Хэ".

Кидай 2000 строк, посмотрю по врмени выполнения.
__________________
Помогаю платно.
Помогаю иногда бесплатно.
Ответить с цитированием
  #5  
Старый 23.03.2012, 20:10
Аватар для YVitaliy
YVitaliy YVitaliy вне форума
Местный
 
Регистрация: 14.12.2011
Сообщения: 481
Версия Delphi: Borland Delphi7
Репутация: 17
По умолчанию

Цитата:
Сообщение от @Rafa3L
Без кода можешь обращаться в "Битву экстрасенсов" или программу "Люди Хэ".

Кидай 2000 строк, посмотрю по врмени выполнения.
Вот посмотрит человек на твою подпись, и не скинет
Я вообще не понял: есть 20 вложенных циклов, а процесс идет в 2х потоках. Это как?
Ответить с цитированием
  #6  
Старый 23.03.2012, 22:52
icsander icsander вне форума
Новичок
 
Регистрация: 17.04.2011
Сообщения: 87
Репутация: 10
По умолчанию

Код в студию. А чтобы программа "не зависала" во время вычислений вставь внутри циклов <Application.ProcessMessages>.
Ответить с цитированием
Этот пользователь сказал Спасибо icsander за это полезное сообщение:
Dogmat-iGwt (24.03.2012)
  #7  
Старый 24.03.2012, 00:28
Аватар для Ferra
Ferra Ferra вне форума
Местный
 
Регистрация: 12.03.2006
Адрес: Минск
Сообщения: 527
Репутация: 1336
По умолчанию

Цитата:
Сообщение от Dogmat-iGwt
Процесс зависит от 20-ти переменных, диапазоны значений которых либо известны изначально, либо зависят друг от друга. Таким образом получается 20 вложенных циклов for.
Я бы не усложнял так код, а сделал бы массив таких диапазонов По идее и скорость может повысить.

Цитата:
Сообщение от Dogmat-iGwt
При стандартном наборе переменных программа вычисляет больше миллиарда вариаций, что занимает у нее больше 12 минут. Процесс идет в 2 потока и грузит 33% ЦП, при этом программа виснет и не отвечает в диспетчере задач.
Всё просто, нужно принудительно обрабатывать сообщения для окна программы от windows. Но это будет тормозить вычисления.
И оно точно в 2 потока работает? Т.е. если оно действительно многопоточное, то почему, например, не 10?

Цитата:
Сообщение от Dogmat-iGwt
Я попытался снизить количество вычислений следующим образом: вычленил некоторые закономерности процесса и, в случае наступления такой закономерности, пропускал последнее обращение к подпрограмме переходя к следующему значению по циклу. Однако время расчета не снизилось даже на секунду, то есть, как я понял, блок, содержащий только условия, ЦП практически не грузит.
Можешь попробовать кэширование или динамическое программирование.

Цитата:
Сообщение от Dogmat-iGwt
Есть ли способ как-то еще снять нагрузку, чтобы снизить время хотя бы до 3,5 минут? Некоторые циклы при определенных условиях содержат всего одно значение, если от них как-нибудь избавиться, то это снизит нагрузку?
Так тут чисто твоя логика должна работать, алгоритм работы ты не показал\не описал а спрашиваешь как оптимизировать
Посмотри на пакеры exe, теоретически могут и ускорить работу. + Могут помочь опции компиляции.
__________________
Нет повести печальнее на свете, чем повесть о заклиневшем Resete.

Последний раз редактировалось Ferra, 24.03.2012 в 00:39.
Ответить с цитированием
Этот пользователь сказал Спасибо Ferra за это полезное сообщение:
Dogmat-iGwt (24.03.2012)
  #8  
Старый 24.03.2012, 00:45
Аватар для YVitaliy
YVitaliy YVitaliy вне форума
Местный
 
Регистрация: 14.12.2011
Сообщения: 481
Версия Delphi: Borland Delphi7
Репутация: 17
По умолчанию

Цитата:
если оно действительно многопоточное, то почему, например, не 10?
С 10ю потоками оно быстрее работало бы только на 10ти ядерном проце) А по сути, с "20 вложенными циклами" - я не представляю, как можно цикл пустить в один поток, а операторы в нем (вложенные циклы) - в иной!
Ответить с цитированием
  #9  
Старый 24.03.2012, 00:52
Аватар для Ferra
Ferra Ferra вне форума
Местный
 
Регистрация: 12.03.2006
Адрес: Минск
Сообщения: 527
Репутация: 1336
По умолчанию

Цитата:
Сообщение от YVitaliy
С 10ю потоками оно быстрее работало бы только на 10ти ядерном проце) А по сути, с "20 вложенными циклами" - я не представляю, как можно цикл пустить в один поток, а операторы в нем (вложенные циклы) - в иной!
Это непрада. Количество ядер почти не имеет значения если программа не оптимизирована специальным образом. Я не знаю, делает ли это компилятор дельфи автоматически, но можешь посмотреть сам.

Но ты путаешь понятия. Например вот посмотри http://www.cyberguru.ru/programming/delphi/threads.html
Если твой алгоритм можно распараллелить - то это прилично ускорит скорость работы.

И необязательно циклы в разных потоках запускать. Просто выдели части алгоритма которые могут выполняться параллельно.
__________________
Нет повести печальнее на свете, чем повесть о заклиневшем Resete.

Последний раз редактировалось Ferra, 24.03.2012 в 00:55.
Ответить с цитированием
Этот пользователь сказал Спасибо Ferra за это полезное сообщение:
Dogmat-iGwt (24.03.2012)
  #10  
Старый 24.03.2012, 09:37
Dogmat-iGwt Dogmat-iGwt вне форума
Прохожий
 
Регистрация: 22.03.2012
Сообщения: 7
Репутация: 10
По умолчанию

Ладно, вот приложил чуть-чуть упрощенную версию проги, рассчитывает только количество вариаций=победы+поражения+ничьи. В коде весь ступор в обработчике главной кнопки, остальное все работает нормально.

Как пользоваться: в каждой из 8-ми панелей нужно выбрать по карте, выбор производится проще всего по имени (верхний левый комбобокс на каждой из 8 панелей). Рекомендую прежде чем нажать вычислить выставить в 2-х комбобоксах с надписью 12 в правом-верхнем и правом-нижнем углах окна цифры поменьше. Уже при значении 8 в каждом из них программа считает около минуты. При 12 количество вариаций переваливает за миллиард, прога виснет надолго.

Если что, не удивляйтесь некоторым моим решениям, я новичок самоучка, заранее спасибо. Советам, не относящимся к сути вопроса, тоже буду благодарен.
Вложения
Тип файла: rar кланз.rar (340.9 Кбайт, 8 просмотров)
Ответить с цитированием
  #11  
Старый 24.03.2012, 09:44
Dogmat-iGwt Dogmat-iGwt вне форума
Прохожий
 
Регистрация: 22.03.2012
Сообщения: 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от YVitaliy
Вот посмотрит человек на твою подпись, и не скинет
Я вообще не понял: есть 20 вложенных циклов, а процесс идет в 2х потоках. Это как?

Это я кстати тоже не догнал почему в 2 потока, но судя по инфе из диспетчера задач, их 2. Грузят они ровно 33% ЦП. У меня трехядерный атлон.
Ответить с цитированием
  #12  
Старый 24.03.2012, 11:39
Аватар для YVitaliy
YVitaliy YVitaliy вне форума
Местный
 
Регистрация: 14.12.2011
Сообщения: 481
Версия Delphi: Borland Delphi7
Репутация: 17
По умолчанию

Я просто думал, что ТС организовал вычисления в 2 треды Насчет 2х потоков в диспетчере, то это винда виновата - второй поток на иные вычисления (интерфейс например). Вот из-за этого и 33% - что 3х ядерный Атлон - процесс идет только на одном ядре, интерфейс не отвечает...
Ответить с цитированием
  #13  
Старый 24.03.2012, 12:47
Аватар для Pilot_Red
Pilot_Red Pilot_Red вне форума
Продвинутый
 
Регистрация: 01.11.2006
Адрес: Карелия
Сообщения: 702
Версия Delphi: D7
Репутация: 11581
По умолчанию

Про логическую оптимизацию ни чего не скажу, т.к. одному автору известно что он задумал, а вот про то как все это организовано могу сказать две вещи.
1. В процедуру fight передается слишком много параметров, поэтому нужно сделать новый тип при помощи оператора record, забить все параметры в этот тип, объявить переменную этого типа, и передавать в процедуру указатель на эту переменную
2. все вычисления которые можно вычислить заранее убери за тело цикла(ов), так как при каждом шаге цикла, у тебя вычисляется одно и тоже. Например:
в коде for i:=1 to 2*cos(2-3)/100/450*43 место, которое выделено нужно рассчитывать заранее, и подставлять в это место заранее вычисленное значение.
Если хотя бы по этим принципам оптимизации пойдешь, получишь видимый эффект!
Ответить с цитированием
Этот пользователь сказал Спасибо Pilot_Red за это полезное сообщение:
Dogmat-iGwt (24.03.2012)
  #14  
Старый 24.03.2012, 13:51
Dogmat-iGwt Dogmat-iGwt вне форума
Прохожий
 
Регистрация: 22.03.2012
Сообщения: 7
Репутация: 10
По умолчанию

Попробую сделать, как вы советуете. Однако возникает вопрос, почему когда я сделал так, чтобы программа перепрыгивала последний fight примерно в 35-40% случаев, то есть отсеял примерно 150 миллионов обращений к подпрограмме из 2 миллиардов, но при этом время вычисления осталось таким же?
Ответить с цитированием
  #15  
Старый 24.03.2012, 14:01
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Зависит от того, как делали. Если использовали много 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;
И так далее. Можно использовать case B2i of.

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)
Ответ


Delphi Sources

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

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

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

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


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


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

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

ВКонтакте   Facebook   Twitter