Что нового

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

CreatoR

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

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 545
Репутация
2 428
Кто нибудь пробовал применить это на деле?

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

kaster

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

CreatoR

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

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

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

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
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 545
Репутация
2 428
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 752
Репутация
1 149
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 752
Репутация
1 149
Новый тест

Код:
$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 545
Репутация
2 428
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 714
Все эти циклы и безусловные переходы в конечном счете сводятся к j* операторам в ассемблере. А какой из них в каком случае применяется, вот это уже вопрос. Еще важно количество кода в пределах If - EndIf.
 
Верх