Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Разница между if, ? и switch/case (http://www.flasher.ru/forum/showthread.php?t=121698)

Psycho Tiger 20.02.2009 19:54

Разница между if, ? и switch/case
 
Интересна разница между ними с точки зрения производительности.
За все своё время программирования плодил тонны if`ов (если нужно), но очень редко пользовался switch/case`ом (мне сложнее его читать). Насколько такой подход был критичен с точки зрения производительности, или компилятор переведет все это в один и тот же байткод?

CrazyFlasher 20.02.2009 19:55

не проверял на скорость, но как раз таки для меня более чтиабельно switch case, чем "тонны if'ов"

etc 20.02.2009 19:57

switch в байткоде и есть тонна строгих if.

_Smirnoff 21.02.2009 00:17

Конструкция

Код AS3:

if (условие)
{
 
}
else if (условие)
{
 
}

вообще вымораживает.

switch/case более читабельней, ведь хороший программист - это тот, кто пишет код понятный другим программистам, а не машине.

iNils 21.02.2009 01:40

Условие условию рознь. switch для случаев, когда условий (с if) больше 2-3 (то есть пост _Smirnoff мимо, иначе слишком громоздко) и в switch можно описать лишь одну ОДНО условие, в иных случахя без if/else if некуда.

DarkLight 21.02.2009 02:19

Цитата:

switch/case более читабельней
для меня switch/case по сравнению с if/else нечитабелен из-за кучи break-ов (я пишу фигурную скобку на той же строке что if/else, а не на отдельной, возможно поэтому), и, соответственно, подлежит использованию, когда break нужен не везде, и тогда switch/case упрощает логику. Одно условие тоже ограничивает применимость. А так как конструкция по смыслу полностью аналогична группе строгих сравнений, я практически никогда ее не использую.

wvxvw 21.02.2009 02:36

Добавлю, что со swtich-case связано несколько багов компилятора, например использование E4X, такая конструкция не прочитается правильно:
Код AS3:

case "foo":
list = xml.(<Boolean>);
...

Нужно обязательно обернуть case "foo": { .... } фигурными скобками. И тогда это действительно выглядит дико :) Но я все равно больше switch-case люблю, потому что если много ифоф подряд - теряешься, какие из них связаны, а какие - нет.

etc 21.02.2009 07:32

_Smirnoff, неа, это как раз плохой программист. Хороший пишет понятно и для тех и для других.

ramshteks 21.02.2009 08:34

Код AS3:

if (условие)
{
 
}
else if (условие)
{
 
}

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

Код AS3:

if (условие)
{
 
}
 
if (условие)
{
 
}

или

Код AS3:

if (условие)
{
 
}
else
{
 
 if (условие)
{
 
}
 
}

на мой взгляд ваш "бесящий" вариант очень хорош, если нужно нумного уточнить условие для ложности первого условия

CrazyFlasher 21.02.2009 12:44

вообще огромное количество больших конструкций if (тоже самое и switch) в небольшом проекте это плохой тон и низкий уровень испрользования фишек ооп...имхо

DarkLight 21.02.2009 13:29

гм, if-ы в бизнес-логике особо не позаменяешь. Часто можно применить Стратегию(Strategy), но в AS это не самый удобный паттерн, из-за отсутствия перегрузки функций в первую очередь. Плохой тон - это множественные точки выхода из функций, разложенные по if-ам.

Psycho Tiger 21.02.2009 15:51

Ну гм... 5 Проверок значения переменной a:
Код AS1/AS2:

switch a
case break;
case break;
case breakl
...

или

Код AS1/AS2:

if (a==...)
else if (a==...)
else if (a==...)
else if (a==...)
else if (a==...)

Мне последний более понятен - я читаю строчку - я ВИЖУ имя переменной, не смотря вверх - и читаю код более быстро. Это в примере выше все просто, а если команд много - то найти свич - это какое то время, а после нужно вернуться в место case`а. Если есть прокрутка кода (т.е. кода этих условий больше, чем на один экран) - это тратит время, согласитесь.
Но как сказал __etc, раз в байткоде это и есть тонны if`ов, то беспокоиться нечего)
Вдогонку: оператор ? тоже рассматривается как if/else?
И кстати проверяет он условия все сверху вниз? Т.е. наиболее вероятные исходы при if/else if следует разместить в самом первом if, чтобы он не просчитывал остальные?
Ну и ещё вдогонку: есть переменные a и b, оба булевы.
Я пишу:
Код:

if (a && b) ...
но могу ведь и
Код:

if (a){
if (b){
...
}
}

Теперь мне интересно, если a=false, то во 2 случае проверка b вообще производиться не будет. А в 1 случае будет? Если нет - это ведь какая никакая экономия CPU =)

Яски 21.02.2009 16:06

В первом случае тоже не будет. Я часто пишу так:
Код AS3:

if (a != null && a.b) {
  // Иначе бы при а == null был бы exception
}


r_r_f_r 21.02.2009 16:10

Цитата:

Сообщение от Psycho Tiger (Сообщение 800126)
Вдогонку: оператор ? тоже рассматривается как if/else?

С учётом того что оператор ? работает быстрее чем if, то нет.
Цитата:

Сообщение от Psycho Tiger (Сообщение 800126)
А в 1 случае будет?

Нет, не будет.

etc 21.02.2009 16:37

В первом случае тоже не будет проверяться.

Что касается операторов и switch/if, то смотрим:

Код AS3:

a = 5 ? 10 : 8;

На выходе:
Код:

                        _as3_pushbyte 5
                        _as3_iffalse offset: 7[#10]
                        _as3_pushbyte 10
                        _as3_convert_d
                        _as3_jump offset: 3[#12]
#10                        _as3_pushbyte 8
                        _as3_convert_d
#12                        _as3_convert_d
                        _as3_setlocal <1>

Код AS3:

if (5) a = 10;
else a = 8;

На выходе:
Код:

                        _as3_pushbyte 5
                        _as3_iffalse offset: 8[#11]
                        _as3_pushbyte 10
                        _as3_convert_d
                        _as3_setlocal <1>
                        _as3_jump offset: 4[#14]
#11                        _as3_pushbyte 8
                        _as3_convert_d
                        _as3_setlocal <1>

Разница в лишней конвертации в первом случае и двойному setlocal во втором. По идее, второй вариант быстрее на миллиграмм.

Теперь switch/if:

Код AS3:

        switch (a) {
                case 4:
                        trace(4);
                case 10:
                        trace(a);
                        break;
                case 8:
                        trace(a);
                        break;
                default:
                        trace(a);
        }

На выходе:

Код:

#14                        _as3_jump offset: 41[#34]
                        _as3_label
                        _as3_findpropstrict trace
                        _as3_pushbyte 4
                        _as3_callpropvoid trace(param count:1)
                        _as3_label
                        _as3_findpropstrict trace
                        _as3_getlocal <1>
                        _as3_callpropvoid trace(param count:1)
                        _as3_jump offset: 94[#57]
                        _as3_label
                        _as3_findpropstrict trace
                        _as3_getlocal <1>
                        _as3_callpropvoid trace(param count:1)
                        _as3_jump offset: 83[#57]
                        _as3_label
                        _as3_findpropstrict trace
                        _as3_getlocal <1>
                        _as3_callpropvoid trace(param count:1)
                        _as3_jump offset: 72[#57]
#34                        _as3_getlocal <1>
                        _as3_setlocal <2>
                        _as3_pushbyte 4
                        _as3_getlocal <2>
                        _as3_ifstrictne offset: 6[#41]
                        _as3_pushbyte 0
                        _as3_jump offset: 38[#55]
#41                        _as3_pushbyte 10
                        _as3_getlocal <2>
                        _as3_ifstrictne offset: 6[#46]
                        _as3_pushbyte 1
                        _as3_jump offset: 25[#55]
#46                        _as3_pushbyte 8
                        _as3_getlocal <2>
                        _as3_ifstrictne offset: 6[#51]
                        _as3_pushbyte 2
                        _as3_jump offset: 12[#55]
#51                        _as3_jump offset: 6[#54]
                        _as3_pushbyte 3
                        _as3_jump offset: 2[#55]
#54                        _as3_pushbyte 3
#55                        _as3_kill <2>
                        _as3_lookupswitch -66(3)[-96, -88, -77, -66]

Аналог (вроде такой, если ничего не путаю):

Код AS3:

        if (a === 4) trace(4);
        if (a === 4 || a === 10) {
                trace(a);
        } else if (a === 8) {
                trace(a);
        } else {
                trace(a);
        }

На выходе:

Код:

#57                        _as3_getlocal <1>
                        _as3_pushbyte 4
                        _as3_ifstrictne offset: 7[#63]
                        _as3_findpropstrict trace
                        _as3_pushbyte 4
                        _as3_callpropvoid trace(param count:1)
#63                        _as3_getlocal <1>
                        _as3_pushbyte 4
                        _as3_strictequals
                        _as3_dup
                        _as3_iftrue offset: 5[#72]
                        _as3_pop
                        _as3_getlocal <1>
                        _as3_pushbyte 10
                        _as3_strictequals
#72                        _as3_iffalse offset: 10[#77]
                        _as3_findpropstrict trace
                        _as3_getlocal <1>
                        _as3_callpropvoid trace(param count:1)
                        _as3_jump offset: 23[#87]
#77                        _as3_getlocal <1>
                        _as3_pushbyte 8
                        _as3_ifstrictne offset: 10[#84]
                        _as3_findpropstrict trace
                        _as3_getlocal <1>
                        _as3_callpropvoid trace(param count:1)
                        _as3_jump offset: 6[#87]
#84                        _as3_findpropstrict trace
                        _as3_getlocal <1>
                        _as3_callpropvoid trace(param count:1)

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

r_r_f_r 21.02.2009 19:41

_etc, научите меня, неуча этому кунгфу:)

Psycho Tiger 21.02.2009 19:47

Ммм, __etc, Спасибо.
Только вот:
Цитата:

Сообщение от r_r_f_r
С учётом того что оператор ? работает быстрее чем if, то нет.

Цитата:

Сообщение от __etc
По идее, второй вариант быстрее на миллиграмм.

Все же, какой?

etc 21.02.2009 19:56

Цитата:

Сообщение от Psycho Tiger (Сообщение 800157)
Все же, какой?

Да без разницы, на самом деле. Если она и есть, то настолько мизерная, что можно пренебречь. Я бы воспользовался первым, если выражение не очень сложное.


r_r_f_r, сначала надо получить черный пояс :)

r_r_f_r 21.02.2009 20:02

Ну чёрный пояс в виде спецификации мне помогает, но что за буковки у тебя написаны, для меня загадка, и они подробней:), подскажи на какой полке бляха чудо пояса лежит:)

etc 21.02.2009 20:14

Да вообще-то это Sothink SWF Decompiler показывает.

r_r_f_r 21.02.2009 20:17

Блин, я думал где-то такая чудо инфа имеется, спасибо:)

SunShadow 21.02.2009 20:18

Читабельность любого кода это больше привычка форматировать код и давать понятные наименования переменным и командам, чем выбирать каким операторами его записывать).
На сколько мне известно анализ любого логического условия выполняется до тех пор пока у результата есть неопределенность:
1. a && b при a=false не будет дальше анализировать b, это излишняя операция
2. a || b при a=true не будет дальше анализировать b, это излишняя операция
и т.д.
Я придерживаюсь такой методики: Если условие простое и выполняется в одну операцию то стараюсь выполнять при помощи ? или if. Когда подразумевается многоступенчатая проверка if elseif ... то предпочитаю switch.
На счет того что не видно какие условия проверки есть простой прием
Код AS3:

var obj:* = event.target;
                                switch (true)
                                {
                                        case obj is Map:
                                                map = obj as Map;
                                                currentScroll = map;
                                                addEventListener(NavigatorEvents.MOUSE_OVER, hnMouseOverChildControl);
                                                break;
                                        case obj is Classificator:
                                                classificator = obj as Classificator;
                                                break;
                                        case obj is ButtonScaleDown:
                                                btnScaleDown = obj as ButtonScaleDown;
                                                addEventListener(NavigatorEvents.SCALE_DOWN_START, hnScaleDownStart);
                                                addEventListener(NavigatorEvents.SCALE_DOWN_STOP, hnScaleStop);
                                                addEventListener(NavigatorEvents.SCALE_DOWN_ENABLED, hnScaleDownEnabled);
                                                addEventListener(NavigatorEvents.SCALE_DOWN_NOT_ENABLED, hnScaleDownNotEnabled);
                                                break;
                                        case obj is ButtonScaleUp:
                                                btnScaleUp = obj as ButtonScaleUp;
                                                addEventListener(NavigatorEvents.SCALE_UP_START, hnScaleUpStart);
                                                addEventListener(NavigatorEvents.SCALE_UP_STOP, hnScaleStop);
                                                addEventListener(NavigatorEvents.SCALE_UP_ENABLED, hnScaleUpEnabled);
                                                addEventListener(NavigatorEvents.SCALE_UP_NOT_ENABLED, hnScaleUpNotEnabled);
                                                break;
                                        default:
                                                throw Error('Неопознанный контрол.');
                                }

Мне читать такой код проще чем череду из if. Сразу видно что и с чем работает. И секцию если она не отрабатывает проще пропустить и найти следующую. И потом у свитча есть такая полезная функция как объединение нескольких условий по пропуску break, что тоже облегчает чтение чем разбирать какие из вложенных if будут работать а какие нет.

Gaen 21.02.2009 21:54

Раз уж пошла такая пьянка, расскажите, как описанные выше способы соотносятся по быстродействию с хешами.

godknowsiamgood 22.02.2009 15:05

Свитч работает гораздо быстрее. Например,

if (val == 1)
...
else if (val == 2)
...

В данном случае проверяются все ифы, пока не дойдет до верного условия.

А в случае с кейсом - компилятор строит такой код, который выполняет некоторые нехитрые арифметические операции с адресами, и таким образом происходит сразу прыжок на нужный код.

Хотя я знаю, что это верно применительно к C++.

BlooDHounD 22.02.2009 15:14

godknowsiamgood, ни к С++ ни к АС ваши слова отношения не имеют.

VVall 22.02.2009 15:27

Насколько я помню, оптимизирующие компиляторы C++ умеют делать таблицы перехода для больших switch (сотни case), вместо набора if'ов.

iNils 22.02.2009 16:13

Цитата:

В данном случае проверяются все ифы, пока не дойдет до верного условия.
А в случае с кейсом - компилятор строит такой код, который выполняет некоторые нехитрые арифметические операции с адресами, и таким образом происходит сразу прыжок на нужный код.
Думаете break просто так пишут?

Psycho Tiger 22.02.2009 21:33

Цитата:

Сообщение от VVall (Сообщение 800264)
Насколько я помню, оптимизирующие компиляторы C++ умеют делать таблицы перехода для больших switch (сотни case), вместо набора if'ов.

Логично было бы тогда все if`ы переводить в switch`и при комплияции, нэ?

2iNils: не понял сути твоего поста =)

VVall 22.02.2009 22:41

Цитата:

Сообщение от Psycho Tiger (Сообщение 800310)
Логично было бы тогда все if`ы переводить в switch`и при комплияции, нэ?

Не в курсе тонкостей, но вроде это связано с кэшем - обращение к таблице медленнее нескольких условий.

godknowsiamgood 22.02.2009 23:51

Цитата:

Сообщение от BlooDHounD (Сообщение 800261)
godknowsiamgood, ни к С++ ни к АС ваши слова отношения не имеют.

Не понимаю. Вот нашел:
It is well known that many C compilers will attempt to convert a switch statement into a jump table.

aksios 23.02.2009 00:32

Полная конструкция оператора switch - переключателя, предпологает наличие переменной, в зависимости от значений которой, ей сопоставляется исчерпывающий набор правил. В этом его суть - дает унифицированный, но часто избыточный код.
Полная конструкция if - условный оператор, служит для построения ветвящихся логических структур, где условия ветвления алгоритма могут иметь более гибкий характер. Такие ветвления более характерны для линейного программирования.

SunShadow 23.02.2009 09:52

Я бы сказал так)
Разница между if, ? и switch/case в том как вы ими пользуетесь) А по сути это одно и то же. Эффективность работы зависит больше от рационально построенного условия чем от того, какой из вариантов для анализа вы выберете.

aksios 23.02.2009 13:00

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

BlooDHounD 23.02.2009 13:03

godknowsiamgood, начнём с того, что сишные компиляторы самые умные в мире. лучше их никто код не оптимизирует. то что Вам где-то написали в открытую, что один кусочек во что-то переделывается, это ещё ничего не значит. на самом деле там переделывается всё и вся. одни тэмплэйты и и таблицы виртуальных методов чего стоят. от оригинального кода там и места живого не остаётся. из-за этого дебажить сишный код может только очень упорный человек, или очень талантливый. в болие-менее сложном проекте, ошибки из-за многоуровневой системы компиляции просто так не понять. на пример, описываете Вы метод add, а в ошибке видите что-то типа My_foo_ASD_namespace_Point_add_My_foo_ASD_namespace_PolatPoint. человек не понимающий всю цепочку работы компилятора, фиг поймёт, что это автосгенерированное имя основанное на куче других автосгенерированных имён, что бы создать уникальность, зато мы имеем темплейты. парой строчек можем описать неизвестное множество сущностей, которые будут создаваться и проверяться не в рантайме (как в джаве или АС3), а на этапе компиляции, и про то что они будут реально типизированы, а не мнимо, я вообще молчу. оптимизация уровня inline-методов, в сях достигла совершенства :) компиляторы начали сами считать какой метод сделать inline. и и даже если Вы сами его таковым не пометите, компилятор может оказаться умнее. и т.д. и т.п. в общем ставить в пример компиляторы си, не стоит. слишком разных размеров ягодки. в такие таблицы вобще не только кэйсы переделываются и не всегда.

Psycho Tiger 23.02.2009 13:04

Цитата:

Сообщение от aksios (Сообщение 800388)
Предположим, нужно проверить переменную - если она вне диапозона, то присвоить ей новое значение и продолжить с ним. - Криво как то писать свич для одного условия.

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

aksios 23.02.2009 13:16

Psycho Tiger, есть сильные сомнения, что свич в таких случаях сработает быстрее, а главное что программист вообще поймет логику работы своего алгоритма. Я к примеру, если вижу свич, то первая мысль - может еще чего в него дописать - подключить, а одиночный иф - видится вроде предохранителя на проводе. (пишу глядя на сетевой фильтр).

SunShadow 23.02.2009 19:53

Построение ранга для запросов
Код AS3:

str = str ? ','+str:str;

Сложные условия
Код AS3:

if (b>c || a<d){
  trace('Победа');
}

ну а свитч это перебор вариантов. Если планируется что в будущем узел с условиями будет расширяться то я предпочитаю использовать свитч, его модифицировать проще чем клубок из ифов. А по поводу того что производительней это боюсь вам даже разработчики не скажут. В каждом отдельном случае эффективность будет определяться множеством условий. Если вам нужна оптимизация ищите в тех местах где этого действительно можно добиться.
Тот же код из первой строчки. Если диапазон большой скажем миллиард значений, то весь миллиард шагов делать проверку того что это первый фрагмент не стоит. Либо первый элемент(без запятой) добавить отдельно, либо просто сложить все значения а первую запятую удалить пост действием. Тем самым вы исключите 1 млрд проверок и замените их на конкатенацию.


Часовой пояс GMT +4, время: 22:10.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.