Что нового

Исследование скорости обработки условных операторов

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Данная тема затрагивалась так или иначе на форуме, но я решил отвести её в отдельное обсуждение.

AZJIO пришёл к следующим результатам:
При логическом False в условии, комбинация в одну строку работает быстрее, поэтому цикл содержащий вероятное условие False и однократный True для выхода из цикла - лучше делать одной строкой.

Вот скрипт показывающий данное утверждение:
Код:
_SpeedTest("_Test_IfThen_OnTrue")
_SpeedTest("_Test_IfThenEndIf_OnTrue")

_SpeedTest("_Test_IfThen_OnFalse")
_SpeedTest("_Test_IfThenEndIf_OnFalse")

Func _Test_IfThen_OnTrue()
	For $i = 1 To 1000000
		If 1 Then $b = False
	Next
EndFunc

Func _Test_IfThenEndIf_OnTrue()
	For $i = 1 To 1000000
		If 1 Then
			$b = False
		EndIf
	Next
EndFunc

Func _Test_IfThen_OnFalse()
	For $i = 0 To 1000000
		If 0 Then $b = False
	Next
EndFunc

Func _Test_IfThenEndIf_OnFalse()
	For $i = 1 To 1000000
		If 0 Then
			$b = False
		EndIf
	Next
EndFunc

Func _SpeedTest($sTestFunc)
	Local $iRepeat_Test = 5
	Local $aTests[$iRepeat_Test+1] = [$iRepeat_Test]
	Local $iTotal_Tests = 0
	
	For $x = 1 To $iRepeat_Test
		$iTimer = TimerInit()
		
		;=== CODE TEST ====
		Call($sTestFunc)
		;=== CODE TEST ===
		
		$aTests[$x] = Round(TimerDiff($iTimer), 3)
		$iTotal_Tests += $aTests[$x]
		ConsoleWrite("Test #" & $x & ": " & $aTests[$x] & " ms" & @LF)
	Next

	$iAverage = Round($iTotal_Tests / $iRepeat_Test, 3)
	ConsoleWrite("======================" & @LF & "Tests Average For [" & $sTestFunc & "]: " & $iAverage & @LF & "======================" & @LF & @LF)
EndFunc


Объясняется это тем, что при условий False, выполняется меньше кода (без $b = False), а в случае с завершающим EndIf, всегда будет исполняться больше кода (из за проверки EndIf).
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Кто нибудь пробовал применить это на деле?

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

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
623
CreatoR [?]
Кто нибудь пробовал применить это на деле?
что конкретно? примеры выше или данный прием с кол-вом строк?
пример я запускал давно, когда только тема появилась, но это было известно давно, еще когда Yashied писал об этом. если второе, то я везде, где можно применяю условные операторы в одну строку – тупо короче. но вообще, как я понял, это поведение из всех известных мне ЯП, свойственно только AutoIt.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Kaster [?]
что конкретно? примеры выше или данный прием с кол-вом строк?
Дело не в количестве строк, а в скорости обработки.

это было известно давно, еще когда Yashied писал об этом
Где? :scratch:

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

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
623
CreatoR [?]
Дело не в количестве строк, а в скорости обработки.
я знаю. применил кол-во строк только для того, чтобы отделить один способ от другого :smile:
тут я ошибся. Yashied говорил о противоположном. вот тут http://autoit-script.ru/index.php?topic=1042.msg7407#msg7407
то стоило бы задуматься над этим.
так я и задумался. поэтому там где важна скорость обработки, я не использую AutoIt в силу сверхвысокого уровня языка :smile:
 

SyDr

Сидра
Сообщения
651
Репутация
158
Вариант с False выполняется быстрее не из-за какого-то странного стечения обстоятельств, а из-за того, что в нём меньше кода выполняется. $b = False в нём никогда не выполняется. Другими словами - бред всё это.

Tests Average For [_Test_IfThen_OnTrue]: 2151.137
Tests Average For [_Test_IfThenEndIf_OnTrue]: 1211.293
Tests Average For [_Test_IfThen_OnFalse]: 432.258
Tests Average For [_Test_IfThenEndIf_OnFalse]: 709.6

Если же во втором тесте убрать выполнение $b = False (в первом этого сделать не получится), то тогда результат:

Tests Average For [_Test_IfThen_OnTrue]: 1857.631
Tests Average For [_Test_IfThenEndIf_OnTrue]: 722.693
Tests Average For [_Test_IfThen_OnFalse]: 414.813
Tests Average For [_Test_IfThenEndIf_OnFalse]: 789.881

Вариант с True оказывается даже быстрее :smile:

А вот в этом тесте вариант с полной записью (IfThenEndIf) у меня оказывается стабильно быстрее:
Код:
_SpeedTest("_Test_IfThen")
_SpeedTest("_Test_IfThenEndIf")

Func _Test_IfThen()
    For $i = 1 To 1000000
        If Random()>0.5 Then $b = 0
    Next
EndFunc

Func _Test_IfThenEndIf()
    For $i = 1 To 1000000
        If Random()>0.5 Then
            $b = 0
        EndIf
    Next
EndFunc

Func _SpeedTest($sTestFunc)
    Local $iRepeat_Test = 10
    Local $aTests[$iRepeat_Test+1] = [$iRepeat_Test]
    Local $iTotal_Tests = 0

    For $x = 1 To $iRepeat_Test
        $iTimer = TimerInit()

        ;=== CODE TEST ====
        Call($sTestFunc)
        ;=== CODE TEST ===

        $aTests[$x] = Round(TimerDiff($iTimer), 3)
        $iTotal_Tests += $aTests[$x]
;~         ConsoleWrite("Test #" & $x & ": " & $aTests[$x] & " ms" & @LF)
    Next

    $iAverage = Round($iTotal_Tests / $iRepeat_Test, 3)
    ConsoleWrite("Tests Average For [" & $sTestFunc & "]: " & $iAverage & @LF)
EndFunc
 

rusreg79

Продвинутый
Сообщения
159
Репутация
57
Вариант с False выполняется быстрее не из-за какого-то странного стечения обстоятельств, а из-за того, что в нём меньше кода выполняется. $b = False в нём никогда не выполняется. Другими словами - бред всё это.
Не бред, вы сравниваете не то, CreatoR в первом посте обращает внимание на сравнение одно строчного кода с много строчным.
 

SyDr

Сидра
Сообщения
651
Репутация
158
Да ну? Перечитал первый пост, понял всё так же, как и раньше. Смысла создавать условный оператор, который никогда не будет выполнять код?
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
SyDr [?]
$b = False в нём никогда не выполняется
Так об этом же и речь, при False оно никогда не выполняется, отсюда и утверждение.

А вот в этом тесте вариант с полной записью (IfThenEndIf) у меня оказывается стабильно быстрее
Ты здесь сравниваешь через Random, это неправильно, там будут разные сравнения, и от этого зависит количество исполняемого кода.


Добавлено:
Сообщение автоматически объединено:

SyDr [?]
Смысла создавать условный оператор, который никогда не будет выполнять код?
Так именно это и утверждается в тестах!
Если условие всегда False, то лучше использовать одну строку (меньше кода - без EndIf), а если True иногда проскакивает, то лучше всё же через EndIf.
 

zlo-kazan

Скриптер
Сообщения
374
Репутация
100
OffTopic:

А кто-нибудь сравнивал... как лучше всего хранить массивы т.е. это SQL/Excel/txt/ini/код программы?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
964
zlo-kazan сказал(а):
OffTopic:

А кто-нибудь сравнивал... как лучше всего хранить массивы т.е. это SQL/Excel/txt/ini/код программы?
IMHO реляционные базы будут быстрее.
 

AZJIO

Меценат
Меценат
Сообщения
2,761
Репутация
1,152
CreatoR [?]
а если True иногда проскакивает, то лучше всё же через EndIf
Даже можно подсчитать отношение, например один True к шести False (сделать в цикле соотношение).

zlo-kazan
так создал бы тему да получил бы ответ, я тоже недавно решал это вопрос, но не стал городить огород с SQL, программка в разы увеличивается в размерах, а ini не поддерживает многострочное значение параметра.
 

SyDr

Сидра
Сообщения
651
Репутация
158
CreatoR [?]
Если условие всегда False, то лучше использовать одну строку (меньше кода - без EndIf)
Если условие всегда False, то всегда лучше вообще не писать эту строку кода. Зачем она нужна? Если же True встречается хотя бы в один раз из 6 (см. AZJIO), то выгоднее писать полную форму.

Но вообще, получается, что если уловие ложно, то краткая форма обрабатывается примерно в 2 раза быстрее, чем полная. Однако это можно объяснить тем, что полная форма более универсальна (можно выполнять блок операторов, есть Else, ElseIf).

0.0000335 - время на обработку пустой кртакой формы If. ИМХО, это не то место, которое необходимо оптимизировать. Если мне покажут реальный пример, тогда может и изменится мнение.
 

AZJIO

Меценат
Меценат
Сообщения
2,761
Репутация
1,152
Новый тест

Код:
$k=3 ; 1 раз True, остальное из указанного количества False
$c1=Int(100000/$k)
$c2=100000-$c1
$z=0
$timer = TimerInit()
For $i = 1 to $c1
	If 1 Then $z=False
Next
For $i = 1 to $c2
	If 0 Then $z=False
Next
$tmp1 = Round(TimerDiff($timer) / 1000, 3)
; MsgBox(0,"Время выполнения", $tmp1 & ' сек')

$z=0
$timer = TimerInit()
For $i = 1 to $c1
	If 1 Then
		$z=False
	EndIf
Next
For $i = 1 to $c2
	If 0 Then
		$z=False
	EndIf
Next
$tmp2 = Round(TimerDiff($timer) / 1000, 3)
; MsgBox(0,"Время выполнения", $tmp2 & ' сек')
If $tmp1>$tmp2 Then
	$z='2 быстрее'
ElseIf $tmp1<$tmp2 Then
	$z='1 быстрее'
ElseIf $tmp1=$tmp2 Then
	$z='одинаково'
EndIf
MsgBox(0, $z, '1 - '&$tmp1 & ' сек'&@CRLF&'2 - '&$tmp2 & ' сек')
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
SyDr [?]
Если условие всегда False, то всегда лучше вообще не писать эту строку кода
Как это, речь про вероятность данного условия. Например при проверке @error, он же будет выполнен только один раз... хотя мы конечно не знаем на каком этапе, это усложняет выявление подходящего метода.

Если же True встречается хотя бы в один раз из 6 (см. AZJIO), то выгоднее писать полную форму
Да нет же, в том то и дело что нет:

Код:
_SpeedTest("TesteIfThen")
_SpeedTest("TestIfThenEndIf")

Func TestIfThen()
	For $i = 1 To 6
		If $i = 1 Then ExitLoop
	Next
EndFunc

Func TestIfThenEndIf()
	For $i = 1 To 6
		If $i = 1 Then
			ExitLoop
		EndIf
	Next
EndFunc


Вариант с IfThen почти в два раза быстрее.
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
964
IMHO всё это понятие относительное!
Нужно как мне кажется смотреть на весь код в целом, если речь идёт о скорости выполнения условных операторов.
Ну, к примеру, возьмем последний пример от CreatoR`а и поменяем местами первые строки.
В таком контексте время на выполнение функции TesteIfThen получает прирост не в два раза, как было сказано выше, а уже в 4~5! ;D
Код:
_SpeedTest("TestIfThenEndIf")
_SpeedTest("TesteIfThen")


Func TestIfThen()
    For $i = 1 To 6
        If $i = 1 Then ExitLoop
    Next
EndFunc

Func TestIfThenEndIf()
    For $i = 1 To 6
        If $i = 1 Then
            ExitLoop
        EndIf
    Next
EndFunc

Func _SpeedTest($sTestFunc)
    Local $iRepeat_Test = 5
    Local $aTests[$iRepeat_Test+1] = [$iRepeat_Test]
    Local $iTotal_Tests = 0
    
    For $x = 1 To $iRepeat_Test
        $iTimer = TimerInit()
        
        ;=== CODE TEST ====
        Call($sTestFunc)
        ;=== CODE TEST ===
        
        $aTests[$x] = Round(TimerDiff($iTimer), 3)
        $iTotal_Tests += $aTests[$x]
        ConsoleWrite("Test #" & $x & ": " & $aTests[$x] & " ms" & @LF)
    Next

    $iAverage = Round($iTotal_Tests / $iRepeat_Test, 3)
    ConsoleWrite("======================" & @LF & "Tests Average For [" & $sTestFunc & "]: " & $iAverage & @LF & "======================" & @LF & @LF)
EndFunc
 

SyDr

Сидра
Сообщения
651
Репутация
158
CreatoR [?]
Как это, речь про вероятность данного условия. Например при проверке @error, он же будет выполнен только один раз... хотя мы конечно не знаем на каком этапе, это усложняет выявление подходящего метода.
Всё. Теперь понял. Но ведь далеко не всегда при @error<>0 нужно делать только одно действие.

Да нет же, в том то и дело что нет
Странный пример. Зачем же вообще цикл, если он только 1 виток делает. А то, что краткая форма сама по себе быстрее это я уже понял.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Все эти циклы и безусловные переходы в конечном счете сводятся к j* операторам в ассемблере. А какой из них в каком случае применяется, вот это уже вопрос. Еще важно количество кода в пределах If - EndIf.
 
Верх