Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.02.17;
Скачать: [xml.tar.bz2];

Вниз

Что быстрее - с процедурами или без них?   Найти похожие ветки 

 
Denis   (2004-02-05 11:55) [0]

Здравствуйте.
По теме оптимизации у меня возник такой вопрос.
Предположим, текст программы состоит из одинаковых блоков кода, ну скажем, создающего одинаковые кнопки с разными координатами. Допустим, мы устанавливаем каждый раз 5-6 свойств для каждой кнопки. И кнопок у нас штук 20. Что будет оптимальнее с точки БЫСТРОДЕЙСТВИЯ - сплошной текст программы, рисующий 20 кнопок, или 20 раз вызвать процедуру с такой же функцией?
Думаю первый вариант будет быстрее, поскольку исключает затраты времени на вызов процедур, передачу параметров и возвращение в программу.
Циклов мы не касаемся в данном случае.
Что думаете (знаете)?


 
Тимохов   (2004-02-05 11:57) [1]

Задумываться о такой оптимизации надо если у тебя 20 млн вызов. Для 20 кнопок делать надо через процедуры.


 
Никто   (2004-02-05 11:57) [2]

Вызов процедуры выполняется намного быстрее, чем прорисовка на экране.


 
Mystic   (2004-02-05 12:01) [3]

Быстрее 20 кнопок рисовать руками на канве и руками отслеживать нажатие на оные.


 
Denis   (2004-02-05 12:09) [4]

Не в кнопках дело. Это пример. Не буду я их рисовать. Зацепились...
Насколько вызов процедуры проигрывает/выигрывает по сравнению с просто выполнением сплошного кода и в каких случаях?


 
Никто   (2004-02-05 12:14) [5]

Тема для курсовой работы.


 
Тимохов   (2004-02-05 12:17) [6]

Меня, правда, самого интересует - сколько тактов занимает стандартный вызов процедур (без параметров и, естессвенно, без возвращаемого результата)?


 
Тимохов   (2004-02-05 12:18) [7]

Тимохов © (05.02.04 12:17) [6]
Поясню, что спрашиваю, про команду asm"а call.


 
Denis   (2004-02-05 12:19) [8]

>Никто (05.02.04 12:14) [5]

>Тема для курсовой работы.

Пользуйся, дарю.


 
Denis   (2004-02-05 12:23) [9]

>Тимохов © (05.02.04 12:17) [6]
Вы более корректно чем я поставили вопрос, спасибо :).
Добавлю - какие есть рекомендации по использованию процедур- контекст, условия и т.п.


 
Тимохов   (2004-02-05 12:24) [10]


> Добавлю - какие есть рекомендации по использованию процедур-
> контекст, условия и т.п.

В параметрах пиши, либо const, либо var. Const ускоряет не для всех типов (т.е. для некоторых типов просто ничего не значит), но для некоторых, например, записей, заставляет компилятор делать так, что передается указатель на запись, а не вся запись запихивается в стек вызова - экономи на лицо.


 
Никто   (2004-02-05 12:34) [11]

Метод (процедура, функция) - логический блок программы. Методы были введены для удобочитаемости программы. Оптимизация вызовов методов - тема многолетних дискуссий и трудов. Форматов вызовов - большое количество: register, pascal, cdecl, stdcall, safecall и др. Их разрабатывали, разрабатывают и будут разрабатывать.

ООП - дальнейшее развитие методологий программирования.

И разрабатывают эти методологии не от нечего делать, а для удобства написания и сопровождения кода.

Мое мнение: если логически участок кода можно выделить в отдельную процедуру, то надо это делать. В противном случае программа может превратится в глупого монстра, которого невозможно будет утихомирить.

Взвесьте:
- скорость работы;
- читабельность;
- сопровождаемость (возможность вносить изменения в код);
- и др.

И решайте: писать сотни строк однородного кода или оформить в виде небольшой процедуры.

По поводу количества циклов при вызове процедуры: надо смотреть дизассемблированный код. Мне лень. Может, у Borland"а что-то по этому поводу есть?


 
Digitman   (2004-02-05 12:35) [12]


> И кнопок у нас штук 20


пусть не кнопки, пусть что-то другое

но при штуках, равных 20-ти то что тебя волнует - ловля блох


 
Mystic   (2004-02-05 12:36) [13]

Для теоретических изысканий бери руководство по интересующей тебя модели процессора. Суммируй там количество тактов на выполнение оформление вызова процедуры. Оцени влияние кэширования (при вызове процедуры сбрасывается кэш команд).

А вообще --- почитай про оптимизацию (развертывание циклов и т. д.) В играх производительность можно улучшить, имхо, до 100% процентов, оптимизируя код программы на критических участках. Почтивсе эти участки уже соптимизированы авторами драйверов, DirectX, OpenGL, ... А в GUI-вызовах ты и процента не получишь...


 
mrcat   (2004-02-05 12:46) [14]

Тимохов © (05.02.04 12:18) [7]
>Поясню, что спрашиваю, про команду asm"а call.
call сохраняет точку возврата (PUSH от 2-х) и делает JMP(от 1 такта)


 
Никто   (2004-02-05 12:49) [15]


> Задумываться о такой оптимизации надо если у тебя 20 млн
> вызов. Для 20 кнопок делать надо через процедуры.

Интересно, а как сделать 20 млн. вызовов без процедур?


 
Тимохов   (2004-02-05 12:55) [16]


> Никто (05.02.04 12:49) [15]

Имелось в виду следуюющее
var
kI: Integer;
begin
for kI := 0 to 20000000-1 do
begin
do something without proc
end;
end;

и

var
kI: Integer;
begin
for kI := 0 to 20000000-1 do
begin
do the same something with proc
end;
end;


 
Mystic   (2004-02-05 13:01) [17]

А может

1: do something without proc
2: do something without proc
3: do something without proc
........
20000000: do something without proc

?


 
Никто   (2004-02-05 13:03) [18]

Прошу прощения, но тогда зачем > Для 20 кнопок делать надо через процедуры? (я цепляюсь к словам?)

Я так понял, речь все же идет о (кнопки только для примера):

Button1 := TButton.Create(Self);
Button1.Parent := Self;
Button1.Caption := "Button1";
Button1.Left := 100;
Button2 := TButton.Create(Self);
...
ButtonN := TButton.Create(Self);
...

Я думаю, в таком случае надо использовать общий метод (процедуру, функцию).


 
Тимохов   (2004-02-05 13:08) [19]


> Никто (05.02.04 13:03) [18]

Кто спорит.
В данном случае, конечно, процедуру.


> mrcat © (05.02.04 12:46) [14]


Не подскажите, где в понятном виде надывать информацию о количестве тактов на каждую команду?


 
Denis   (2004-02-05 13:24) [20]

Тимохов © (05.02.04 12:24) [10]

>В параметрах пиши, либо const, либо var.

А если я вызываю процедуру со списком параметров без указния var или const, что в этом случае делает компилятор? Рассматривает параметры как константы?


 
Тимохов   (2004-02-05 13:34) [21]

cosnt - это почти тот же var (т.е. передача по ссылке).
Отличие в том, что при const на стадии компиляции пресекает попытки программиста модифицировать этот параметр.
Тем самым компилятор может спокойненько передавать указатель на исходные данные не боясь, что в процедуре их поменяют. А указатель, как извесно - 4 байта, что существенно меньше чем передавать целиком запись (record) из 200 (например) байт.


 
Никто   (2004-02-05 13:39) [22]


> Не подскажите, где в понятном виде надывать информацию о
> количестве тактов на каждую команду?


http://www.intel.com/design/pentium4/manuals/


 
Denis   (2004-02-05 13:48) [23]

Тимохов © (05.02.04 13:34) [21]

Я понимаю эту разницу. Я о другом.
Вот я пишу: Procedure MyPr(a:integer; b:real);
Здесь я не указываю ключевое слово "var" или "const".
Что есть a и b в данном случае?


 
AKul   (2004-02-05 13:51) [24]


> Denis © (05.02.04 11:55)

При вызове процедуры происходят следующие действия:

Передача параметров вызываемой процедуре (запись в стек или регистры) (если требуется);
Вызов процедуры (call);

Сохранение "нужных" регистров (если требуется);
Выделение места в стеке под локальные переменные (если требуется);

Выполнение кода процедуры....

Освобождение стека, занятого под локальные переменные (^);
Восстановление сохраненных регистров;(^)
Возврат из процедуры;
Освобождение стека, занятого передаваемыми параметрами (^);

Как видите - вынесенный из тела процедуры код будет выполняться быстрее.
Но задумайтесь: стоит ли это того?
Как Вы думаете, заметит ли пользователь, что в новой версии Вашей программы его любимое "окошко" создается на 100 тактов процессора быстрее ( < мкс), чем в предыдущей версии? Но при этом Вы гораздо больше потратили времени на написание/редактирование/отладку создания 20 кнопок без процедур и циклов.
А вот в критичном к быстродействию коде больший эффект будет от изменения алгоритма (в лучшую сторону, конечно), применения технологии параллельной обработки данных (MMX, SSE...) и т.д.

Так что, не стоит отказываться от выноса какого-нибудь логического блока в процедуру только потому, что он будет выполняться на 0,01% (например) медленнее.
В то же время, не стоит и выносить в процедуры все то, что предстает Вашему взору при просмотре исходного текста Вашей программы.
Как Вам написал Никто (05.02.04 12:34) [11]:

> Взвесьте:
> - скорость работы;
> - читабельность;
> - сопровождаемость (возможность вносить изменения в код);
> - и др.
>
> И решайте: писать сотни строк однородного кода или оформить
> в виде небольшой процедуры.


 
AKul   (2004-02-05 13:57) [25]


> Denis © (05.02.04 13:48) [23]
> Вот я пишу: Procedure MyPr(a:integer; b:real);
> Здесь я не указываю ключевое слово "var" или "const".
> Что есть a и b в данном случае?

Это значения переменных, используемых при вызове MyPr, размещенные в стеке (правда a:integer, например, может быть в регистре - зависит от соглашения об вызове).


 
Denis   (2004-02-05 14:09) [26]

AKul © (05.02.04 13:51) [24]
Спасибо, все теперь понятно. Вы замечательно все обьяснили.

AKul © (05.02.04 13:57) [25]
>Это значения переменных, ...
Можно немножко подробнее?
Значит таки компилятор рассматривает эти параметры как переменные и при передаче записи передается вся структура а не указатель на нее?
Этот момент мне не совсем понятен.


 
Тимохов   (2004-02-05 14:15) [27]


> Я понимаю эту разницу. Я о другом.
> Вот я пишу: Procedure MyPr(a:integer; b:real);
> Здесь я не указываю ключевое слово "var" или "const".
> Что есть a и b в данном случае?


Мой Вам добрый совет - если не предполагате внутри метода испозовать праметр как локальную переменную (т.е. менять значения НЕ с целью возврата результата), то пишите const.
Когда будет можно эту директиву компилятор вопримет для оптимизации. Это скажется далеко не по всех случаях, но в тех, в которых можно компилятор обязательно воспользуется этим.

Пример

trec = record
a,b,c: integer;
d,t,g,y: string;
end;

procedure b1(const a: trec);
begin
end;

procedure b2(a: trec);
begin
end;

procedure TForm1.Button4Click(Sender: TObject);
var
a: trec;
begin
b1(a);
b2(a);
end;


Отключите оптимизацию и посмотрите в CPU насколько по-разному делаются вызовы b1 и b2.

В случае MyPr(a:integer; b:real); - разницы нет - все будет передаваться через стек.


 
Тимохов   (2004-02-05 14:22) [28]

Поправка к Тимохов © (05.02.04 14:15) [27]
Виноват, сказал немного не то - вызовы одинаково будут идти - по ссылке, но по разному будет обработка внутри методов.

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


 
Denis   (2004-02-05 14:45) [29]

2 Тимохов ©

Честно говоря, раньше эта проблема меня не особо волновала, const я использовал крайне редко. Вы заставили меня задуматься. Дело в том что у меня 17 вызовов процедур, в каждую из которых при построении отчета передаются ссылки на экземпляры объектов и устанавливаются их свойства и создаются дочерние объекты. Вызов - по форме
....
var RTitle:TfrBandViev;
begin
...
MyPr(RTitle, ...);
...
end;

Я считал, что в данном случае я передаю указатель на экземпляр, а не структуру целиком. Впрочем, даже если это и не так, передать как const все равно нельзя, так как нужно изменять свойства объекта...


 
Тимохов   (2004-02-05 14:51) [30]


> Denis © (05.02.04 14:45) [29]

Про экземпляты объектов я ничего не говорил. Речь шла про структуры (record).
Конечно в объектах передается ссылка.


 
Тимохов   (2004-02-05 14:54) [31]


> > Denis © (05.02.04 14:45) [29]

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


 
AKul   (2004-02-05 14:55) [32]


> Denis © (05.02.04 14:09) [26]
> Вот я пишу: Procedure MyPr(a:integer; b:real);
> Здесь я не указываю ключевое слово "var" или "const".
> Что есть a и b в данном случае?

Если Вы не указали никакого ключевого слова, то в теле процедуры Вы будете оперировать с КОПИЕЙ переданного параметра, т.е. изменение параметра в теле процедуры не повлечет изменения переменной, которая являлась параметром при вызове процедуры (в данном случае передаваться может и константа).
При указании ключевого слова "var", передается АДРЕС переменной и все операции над параметром в теле процедуры будут производиться с переменной, которая являлась параметром при вызове процедуры (в данном случае константа не может передаваться). Используется для возврата процедурой каких-либо значений.

Сами понимаете, что при передаче в параметрах больших структур данных (не integer, как Вы привели в примере), при описании параметров без ключевых слов var, const, на копирование данных в стек требуется время (да и стек). Если же описать параметр как var, то в стек копируется только адрес структуры (т.е. всего 4 байта), Но с другой стороны, описав параметр как var, Вы выиграете в быстродействии, но случайно/преднамеренно можете изменить его (параметр), что приведет к нежелательному изменению структуры, используемой при вызове.
Вот для защиты от таких "случайностей" и служит const.


 
AKul   (2004-02-05 14:59) [33]


> Тимохов © (05.02.04 14:54) [31]
>
> И вообще имхо вы зря одумляетесь о таких вещах - это не
> ваш случай. Не думаю, что вам прямо так нужна эта оптимизация.
> Вы ее врядли ощутите. Мой совет - делайте дело. Когда придет
> время оптимизации, сами во всем разберетесь...


Полностью солидарен!


 
VMcL   (2004-02-05 15:04) [34]

>>Тимохов © (05.02.04 14:15) [27]

> В случае MyPr(a:integer; b:real); - разницы нет - все будет передаваться через стек.

Нет. Зависит от соглашения о вызовах. По умолчанию register => a:Integer - через регистр, b:real - через стек.


 
Тимохов   (2004-02-05 15:13) [35]


> . По умолчанию register => a:Integer - через регистр, b:real
> - через стек.

Имелось в виду, что в данном случае const не влияет никак.


 
Denis   (2004-02-05 15:37) [36]

Тимохов © (05.02.04 14:54) [31]

>И вообще имхо вы зря одумляетесь о таких вещах ...

Возможно, в данном конкретном случае-зря.
Но... интересно - как правильно. Вот и задумался.
Тот кто не задумывается, имхо, никогда не напишет хороший код.
Это только мое имхо.

P.S. Мне нравится эта ветка. Достаточно редко появляется нечто настолько информативное для автора вопроса. Спасибо.


 
Sandman25   (2004-02-05 15:45) [37]

Только стоит еще упомянуть, что при передаче длинных строк (AnsiString, WideString и обычно string) лучше сразу задуматься об оптимизации и обязательно написать либо const, либо var.


 
Тимохов   (2004-02-05 15:50) [38]


> Sandman25 © (05.02.04 15:45) [37]

Да лучше всегда писать const - тогда точно не забудешь когда нужно. Я так делаю всегда. Правда с этим const бывает недокумментировання фигня: когда передаешь интерфейс - не вызывается _AddRef. Последний факт тут как-то обсуждался - решения так и не было, т.е. в документации упоминание этого факта найдено не было


 
Sandman25   (2004-02-05 15:55) [39]

[38] Тимохов © (05.02.04 15:50)

Я тоже всегда пишу const. Про интерфейсы не знал, спасибо.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2004.02.17;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.008 c
1-53543
JediMaster
2004-02-05 12:51
2004.02.17
Сложение чисел в 2ичной системе счислени!


1-53482
Max_Ivanych
2004-02-06 10:32
2004.02.17
Как можно передать сообщение DOS-программе?


6-53666
BPK
2003-12-13 23:43
2004.02.17
Как получить все IP-адреса, связанные с хостом?


9-53347
greenrul
2003-08-08 00:43
2004.02.17
Покритикуйте идею игры.


1-53567
Barbariska
2004-02-09 08:26
2004.02.17
Экспорт данных в Excel





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский