:: Игры Разума
Сравнение циклов
Foxtrot
Автор

Сообщений: 3408
Откуда: Куда:
Дата регистрации: 25.04.2003
Итак, имеем два разных по "размеру" вложенных цикла:
первый допустим от 0 до 123, а второй от 0 до 123456789
внимание вопрос: который из двух вариантов отработает быстрее другого?
вариант 1:
FOR i=0 TO 123
FOR y=0 TO 123456789
ENDFOR
ENDFOR
вариант 2:
FOR y=0 TO 123456789
FOR i=0 TO 123
ENDFOR
ENDFOR
PS: попробуйте сначала дать ответ и только потом проводить тестирования в среде фокса ;)


------------------
Мойте ноги, моя ноги вы моете и руки
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi Канат!

Ты и не представляешь насколько "тонкий" предмет затронул Очень многое зависит от порядка создания переменных - и вообще от "внешних факторов" - даже от того как ты замеряешь скорость исполнения этого куска кода
А "в общем" принципиальной разницы нету - будет быстрее, если доступ к переменной "большего" цикла будет быстрее и медленнее в противном случае. А порядок следования циклов будет не столь важен.
Банально сравни:
LOCAL lnsec
lnsec=SECONDS()
LOCAL i,y
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
? SECONDS()-m.lnsec
и
LOCAL lnsec
lnsec=SECONDS()
LOCAL y, i
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
? SECONDS()-m.lnsec


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Сравнение циклов
PaulWist

Сообщений: 14618
Дата регистрации: 01.04.2004
Опа, я отказываюсь это понимать, здесь что важен принцип FIFO/LIFO при создании переменных - неожиданно.


------------------
Есть многое на свете, друг Горацио...
Что и не снилось нашим мудрецам.
(В.Шекспир Гамлет)
Ratings: 0 negative/0 positive
Re: Сравнение циклов
matod

Сообщений: 3062
Откуда: Иркутск
Дата регистрации: 31.10.2001
Дык. Интерпретатор все-таки. Переменную объявили - ее имя в табличку вмесие со ссылкой на данные. Надо значение - ищем по табличке (бинарным поиском, надеюсь ). Находим имя, затем по ссылке данные.
Компилятор имя вообще не стал бы хранить, поэтому там разница была бы абсолютно несущественна.
Это плата за "динамический" код - макроподстановки, ExecScript() и т.п.
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi matod!

Ну да Из этой же оперы сравнение производительности доступа к переменной через var против m.var - там на результат влияет (что вполне логично если слегка поразмыслить) количество полей в текущем курсоре.

А что касается компилятора - то тоже не всё так просто - ведь во время исполнения данные находятся в регистрах процессора а не в памяти - и соответственно если свободного регистра нет - т.е. приходится данные помещать в память (обычно локальные переменные в стеке сидят) - производительность заметно падает.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Сравнение циклов
matod

Сообщений: 3062
Откуда: Иркутск
Дата регистрации: 31.10.2001
Цитата:
А что касается компилятора - то тоже не всё так просто
Угу. Только это большое счастье занять регистр процессора под переменную. Ведь переменных много, а регистров нет. Производительность падает, но это все равно лучше, поскольку компилятор заменяет обращение к переменной работой с физическим адресом, без всяких циклов поиска...

Можно предположить также что на скорость выполнения будут влиять и другие команды, формирующие списки в памяти - последовательность файлов в SET PATH, SET CLASSLIB и их количество, а также команды в которых имеются альтернативные способы поиска объектов, например do или вызовы UDF - быстрее будут выполнятся те, которые в списке поиска команды стоят раньше.
Ratings: 0 negative/0 positive
Re: Сравнение циклов
leonid

Сообщений: 3204
Откуда: Рига
Дата регистрации: 03.02.2006
Igor Korolyov
Ты и не представляешь насколько "тонкий" предмет затронул

Мне кажется, что кроме "тонкой" компоненты здесь есть и более "грубый" подтекст. Поскольку фокс - интерпретатор, то при исполнении кода
LOCAL lnsec
lnsec=SECONDS()
FOR y=0 TO 123
FOR i=0 TO 1234567
ENDFOR
ENDFOR
? SECONDS()-m.lnsec

оператор
FOR y=0 TO 123
выполнится 1 раз, оператор
FOR i=0 TO 1234567
выполнится 123 раза, первый
ENDFOR
выполнится 123*1234567 раз, и последний
ENDFOR
выполнится 123 раза.

А при выполнении кода
LOCAL lnsec
lnsec=SECONDS()
LOCAL y, i
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
? SECONDS()-m.lnsec

оператор
FOR y=0 TO 1234567
выполнится 1 раз, оператор
FOR i=0 TO 123
выполнится 1234567 раза, первый
ENDFOR
выполнится 123*1234567 раз, и последний
ENDFOR
выполнится 1234567 раза.

Т.е. основная разница по времени будет достигаться на втором операторе FOR и на последнем ENDFOR. Это особенно заметно, если 123 заменить на 1.
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Foxtrot
Автор

Сообщений: 3408
Откуда: Куда:
Дата регистрации: 25.04.2003
ответ верный, все дело в количестве выполнений команд
а насчет переменных скажу лишь одно, поиск переменных в памяти тут совсем ни причем
вспомним классика "горе от ума"


------------------
Мойте ноги, моя ноги вы моете и руки
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi leonid & Канат!

Банальное сравнение "количества выполнений команды" не даёт адекватного представления о скорости работы программы. Даже для машинных инструкций, время исполнения разных команд может отличаться в разы! Что уж говорить про интерпретатор, когда каждая инструкция это по сути вызов процедуры - ты же не будешь спорить что вызвать 1000 раз "быструю" процедуру будет эффективнее чем 10 раз вызвать "медленную" (даже если это одна и та же процедура, просто с разными параметрами). А тут как раз похожая ситуация - время исполнения одной и той же "внутренней процедуры" существенно различается.
Что есть FOR...ENDFOR?
- создание переменной, если её не было (1 раз)
- присвоение начального значения (1 раз)
- проверка на выполнение граничного условия (много раз)
При этом самое "тяжелое" действие связано именно с доступом к переменной цикла - поэтому время этого доступа и будет определяющим.

Конечно "присвоение" значения это тоже небыстрый процесс (т.е. разница конечно будет), однако не думаю что в общем времени исполнения тестового кода это занимает заметный процент. Особенно учитывая что в нормальных программах не бывает таких "пустых циклов". По крайней мере у меня (под VFP9 SP1) разница при "перестановке границ" между 123 и 1234567 составляет около 10%, а при перестановке объявления переменных в LOCAL - 300% IMHO это заметить гораздо проще нежели 10%
Конечно если довести пример до абсурда и сравнивать цикл в 1 итерацию (который вообще-то и не нужен тогда) с циклом в 10E8 итераций то разница будет гораздо существеннее


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Сравнение циклов
leonid

Сообщений: 3204
Откуда: Рига
Дата регистрации: 03.02.2006
Hi, Igor
Сейчас прямо проверил еще раз. Со сменой локальных переменных у меня (шестой фокс) разница никак не составляет больше 2-3 процентов. При "перестановке границ" между 123 и 1234567 у меня тоже получается что-то около 10, но если 123 уменьшать, то разница начинает расти, и в общем где-то пропорционально тому, как изменяется количество операций. Если число 123 достаточно большое, то почти все затраченное время приходится на первый ENDFOR (он выполняется очень много раз, причем одинаковое в обоих случаях), поэтому разница во времени не очень велика.
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi leonid!

Естественно что результат зависит от версии фокса - возможно что в 6-ке оно вообще никогда не будет заметно, возможно что повлияет дополнительная переменная (по тупому - в одном из моих тестов добавление "внешнего" однопроходного цикла - т.е. по сути добавление "лишнего" кода - выправило ситуацию и время исполнения перестало зависеть от порядка переменных в LOCAL). Я к тому и говорю - что тема эта слишком тонкая - зависит от особенностей реализации внутренних процедур в разных версиях фокса.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Сравнение циклов
leonid

Сообщений: 3204
Откуда: Рига
Дата регистрации: 03.02.2006
Hi Igor!

Конечно, факторов влияющих на скорость очень много, и который из них где сильней проявится, наверное не знают даже разработчики. Кое что можно понять, ставя разные эксперименты, и это полезно, поскольку развивает "интуицию". То, что изменение порядка локальных переменных может измень скорость в разы, знать безусловно полезно. Я как то раньше над этим не задумывался.
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi leonid!

Цитата:
Я как то раньше над этим не задумывался
Я тоже Тем более что в реальном применении такая ситуация (пустой цикл) настолько маловероятна... А если цикл не пустой то наверняка и результат будет иной.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Foxtrot
Автор

Сообщений: 3408
Откуда: Куда:
Дата регистрации: 25.04.2003
мона подвести наверное итоги
а они имхо таковы, что если один из вариантов уже сейчас медленнее при пустых-то проходах, то заполнеие какимнить кодом только усугубит ситуацию
всем спасибо
зы если всеж переменные смущают, попробуйте заменить циклы на сканы ;)


------------------
Мойте ноги, моя ноги вы моете и руки




Исправлено 1 раз(а). Последнее : Foxtrot, 13.07.07 12:05
Ratings: 0 negative/0 positive
Re: Сравнение циклов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi Канат!

Напротив - заполнение кодом сведёт разницу к минимуму. Например пустые циклы в 12/1234567 итераций при перестановке имеют разницу почти в 2 раза (1.25 против 0.64 секунды), а при заполнении внутреннего цикла всего 2-мя командами
lnSum = lnSum + 1
REPLACE n1 WITH m.lnSum
Разница составялет всего-то около 5% (23.2 против 22.2 секунды).

Вот что существенно - так это содержимое внешнего цикла (помимо самого внутреннего цикла естественно) - ибо число его исполнений прямо зависит от числа итераций внешнего цикла. Но тут уже дело касается логики - нельзя "просто так" менять местами внешний и внутренний циклы. А если внешний всегда пуст - то и смысла в нём нету никакого - т.е. достаточно всего одного цикла с соответствующим числом итераций.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Сравнение циклов
h.i.a.

Сообщений: 4002
Откуда: Мурманск/Спб/Мск
Дата регистрации: 18.11.2005
Что-то подкрутили в девятке:
VFP 8 sp1: 11 против 9 сек.
VPF 9 sp1: 23 против 9 сек.
Ratings: 0 negative/0 positive
Re: Сравнение циклов
h.i.a.

Сообщений: 4002
Откуда: Мурманск/Спб/Мск
Дата регистрации: 18.11.2005
А как Вам такой фокус ?
SET TALK OFF
? "------"
f1()
f2()
LOCAL a
FOR a=1 TO 1
f1()
f2()
next
FUNCTION f1
LOCAL lnsec
lnsec=SECONDS()
LOCAL i,y
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
? SECONDS()-m.lnsec
ENDFUNC
FUNCTION f2
LOCAL lnsec
lnsec=SECONDS()
LOCAL y, i
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
? SECONDS()-m.lnsec
ENDFUNC
Ratings: 0 negative/0 positive
Re: Сравнение циклов
h.i.a.

Сообщений: 4002
Откуда: Мурманск/Спб/Мск
Дата регистрации: 18.11.2005
Ну и напоследок удар ниже пояса...
SET TALK OFF
? "------"
f1()
f2()
LOCAL a
FOR a=1 TO 1
f1()
f2()
next
FUNCTION f1
LOCAL lnsec
lnsec=SECONDS()
public i,y
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
RELEASE i,y
? SECONDS()-m.lnsec
ENDFUNC
FUNCTION f2
LOCAL lnsec
lnsec=SECONDS()
public y, i
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
RELEASE y,i
? SECONDS()-m.lnsec
ENDFUNC
P.S. Кто теперь скажет, что public - зло ?



Исправлено 1 раз(а). Последнее : h.i.a., 13.07.07 17:23
Ratings: 0 negative/0 positive
Re: Сравнение циклов
h.i.a.

Сообщений: 4002
Откуда: Мурманск/Спб/Мск
Дата регистрации: 18.11.2005
Вот еще информация к размышлению:
SET TALK OFF
? "------"
public lnsec
f1()
f2()
public a
FOR a=1 TO 1
f1()
f2()
next
FUNCTION f1
lnsec=SECONDS()
local i,y
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
? SECONDS()-m.lnsec
ENDFUNC
FUNCTION f2
lnsec=SECONDS()
local y, i
FOR y=0 TO 1234567
FOR i=0 TO 123
ENDFOR
ENDFOR
? SECONDS()-m.lnsec
ENDFUNC
Ratings: 0 negative/0 positive
Re: Сравнение циклов
matod

Сообщений: 3062
Откуда: Иркутск
Дата регистрации: 31.10.2001
Занятно... Попробовал эти три теста на одной машине на VFP6 и VFP9.
Для VFP 6.0 SP5 ситуация следующая:
1-й тест:
8.437
8.516
8.437
8.469
2-й тест
8.469
13.656
8.469
13.594
3-й тест:
8.469
8.437
8.422
8.422
Т.е. порядок создания переменных в данном случае значения практически не имеет. Использование глобальных переменных почему-то во второй функции ухудшило результат, т.е. глобальные переменные в 6-ке - все же зло .
В VFP9 SP1 картина совсем другая:
1-й тест:
8.688
20.578
20.281
8.656
2-й тест:
8.609
8.547
8.625
8.563
3-й тест
8.516
8.547
8.547
8.562
т.е. в 9-ке в первом тесте получил уже весьма существенные тормоза. А наличие глобальной переменной стабилизирует ситуацию. Причем странные какие-то - я бы понял, если бы результат был 8-20-8-20, т.е. тормозила бы функция с другим порядком переменных. Но получилось именно так 8-20-20-8

Тесты запускал по несколько раз в разной последовательности. Результат неизменен с точностью до 0.1 секунды.
Интересно, что в 6-ке добавление в первом тесте в функциях еще 2-х десятков локальных переменных практически не повлияло на результат - те же 8 сек с копейками, что, конечно, противоречит моей гипотезе о потере времени в цикле при поиске переменной. Можно предположить, что при работе цикла for на каждой итерации нет необходимости "искать" переменную - фокс "помнит" ее адрес на время выполнения цикла.
Ratings: 0 negative/0 positive


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

On-line: 5 (Гостей: 5)

© 2000-2024 Fox Club 
Яндекс.Метрика