Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Что быстрее if'ы или switch'и? 
V
    Опции темы
Royan
Дата 1.9.2009, 13:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Dreamer
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 14.9.2002
Где: Лондон

Репутация: 3
Всего: 15



Держу пари на 5 золотых, что никто не проверял это на практике smile Я из чистого любопытства написал, простенький тест, и чтобы он был более объективен, хотел бы попросить всех желающих прогнать его у себя на машине.
Код теста:
Код

package test;

import java.util.Random;

public class Test {

    final static int LEN = 100000000;

    final static int SET = 100;

    private static long totalTimeDefinedIf = 0;
    private static long totalTimeRandomIf = 0;
    private static long totalTimeDefinedSwitch = 0;
    private static long totalTimeRandomSwitch = 0;

    public static void main(String[] args) {
        Random r = new Random(System.currentTimeMillis());
        int[] randomArr = new int[LEN];
        for (int i = 0; i < randomArr.length; i++) {
            randomArr[i] = r.nextInt(10);
        }

        

        for (int i = 0; i < SET; ++i) {
            System.err.println(String.format("Percent done: %.0f%%", (double)i/SET * 100));
            iterateIfs(randomArr, r);
            iterateSwitches(randomArr, r);
        }
        
        
        System.err.println("DefinedIf,RandomIf,DefinedSw,RandomSw");
        
        System.err.println(String.format("%.2f,%.2f,%.2f,%.2f",
                (double) totalTimeDefinedIf / SET, 
                (double) totalTimeRandomIf / SET, 
                (double) totalTimeDefinedSwitch / SET,
                (double) totalTimeRandomSwitch / SET)
        );
    }

    private static void iterateIfs(final int[] randomArr, final Random r) {
        final long start = System.currentTimeMillis();
        for (int i = 0; i < randomArr.length; i++) {
            int temp = -1;
            if (0 == randomArr[i]) {
                temp = 0;
            } else if (1 == randomArr[i]) {
                temp = 1;
            } else if (2 == randomArr[i]) {
                temp = 2;
            } else if (3 == randomArr[i]) {
                temp = 3;
            } else if (4 == randomArr[i]) {
                temp = 4;
            } else if (5 == randomArr[i]) {
                temp = 5;
            } else if (6 == randomArr[i]) {
                temp = 6;
            } else if (7 == randomArr[i]) {
                temp = 7;
            } else if (8 == randomArr[i]) {
                temp = 8;
            } else if (9 == randomArr[i]) {
                temp = 9;
            } else {
                temp = randomArr[i];
                System.err.println("Err: " + temp);
            }
        }

        final long switchStart = System.currentTimeMillis() - start;
        totalTimeDefinedIf += switchStart;

        
        
        
        
        final long randomStart = System.currentTimeMillis();
        for (int i = 0; i < randomArr.length; i++) {
            final int rnd = r.nextInt(10);
            int temp = -1;
            if (0 == rnd) {
                temp = 0;
            } else if (1 == rnd) {
                temp = 1;
            } else if (2 == rnd) {
                temp = 2;
            } else if (3 == rnd) {
                temp = 3;
            } else if (4 == rnd) {
                temp = 4;
            } else if (5 == rnd) {
                temp = 5;
            } else if (6 == rnd) {
                temp = 6;
            } else if (7 == rnd) {
                temp = 7;
            } else if (8 == rnd) {
                temp = 8;
            } else if (9 == rnd) {
                temp = 9;
            } else {
                temp = rnd;
                System.err.println("Err: " + temp);
            }
        }
        
        final long endRndIfStart = System.currentTimeMillis()
        - randomStart;

        totalTimeRandomIf += endRndIfStart;

    }

    private static void iterateSwitches(final int[] randomArr, final Random r) {

        final long switchStart = System.currentTimeMillis();
        for (int i = 0; i < randomArr.length; i++) {
            int temp = -1;
            switch (randomArr[i]) {
            case 0:
                temp = 0;
                break;
            case 1:
                temp = 1;
                break;
            case 2:
                temp = 2;
                break;
            case 3:
                temp = 3;
                break;
            case 4:
                temp = 4;
                break;
            case 5:
                temp = 5;
                break;
            case 6:
                temp = 6;
                break;
            case 7:
                temp = 7;
                break;
            case 8:
                temp = 8;
                break;
            case 9:
                temp = 9;
                break;
            default:
                temp = randomArr[i];
                System.err.println("Err: " + temp);
            }
        }
        
        
        
        

        final long endSwitchStart = System.currentTimeMillis() - switchStart;
        totalTimeDefinedSwitch += endSwitchStart;

        final long rndSwitchStart = System.currentTimeMillis();
        for (int i = 0; i < randomArr.length; i++) {
            final int rnd = r.nextInt(10);
            int temp = -1;
            switch (rnd) {
            case 0:
                temp = 0;
                break;
            case 1:
                temp = 1;
                break;
            case 2:
                temp = 2;
                break;
            case 3:
                temp = 3;
                break;
            case 4:
                temp = 4;
                break;
            case 5:
                temp = 5;
                break;
            case 6:
                temp = 6;
                break;
            case 7:
                temp = 7;
                break;
            case 8:
                temp = 8;
                break;
            case 9:
                temp = 9;
                break;
            default:
                temp = rnd;
                System.err.println("Err: " + temp);
            }
        }

        final long endRndSwitchStart = System.currentTimeMillis()
                - rndSwitchStart;
        totalTimeRandomSwitch += endRndSwitchStart;
    }
}


Тест идет около 15 минут, поэтому просьба проявить терпение. В результатах присутствует 4 метрики
  •  DefinedIf -- Среднее время работы условий на массиве 
  •  RandomIf -- Среднее время работы условий на случайных данных
  •  DefinedSw -- Среднее время работы switch на массиве 
  •  RandomSw -- Среднее время работы switch на случайных данных
 

Случайные данные используются для того, чтобы немного спутать Advanced Branch Prediction

В ответах просьба указать выхлоп, ось и ваш CPU

Мои результаты
Java: Java™ SE Runtime Environment (build 1.6.0_14-b08) Java HotSpot™ Server VM (build 14.0-b16, mixed mode)
OS: Ubuntu 9.04
CPU: Core™2 Duo CPU     P8600  @ 2.40GHz
Цитата

DefinedIf,RandomIf,DefinedSw,RandomSw
1253.61,3060.33,1198.82,3190.20



Это сообщение отредактировал(а) Royan - 1.9.2009, 18:27


--------------------
Открыта вакансия Junior Java Developer'а в нашем лондонском офисе, подробнее можно узнать здесь
PM MAIL MSN   Вверх
Hidrag
Дата 1.9.2009, 14:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 877
Регистрация: 9.4.2005
Где: JDK

Репутация: 3
Всего: 25



как то раз я декомпилировал свой код (потерял исходники) так в нем увидел что при компиляции мои ифы были заменены на свитчи, и многие циклы были изменены на while(true) с условием на брик внутри


--------------------
user posted image
PM WWW ICQ   Вверх
LSD
Дата 1.9.2009, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата
Что быстрее if'ы или switch'и?

Ну учитывая наличие достаточно неплохого JIT, не думаю что там будет какая-то существенная разница.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Royan
Дата 1.9.2009, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Dreamer
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 14.9.2002
Где: Лондон

Репутация: 3
Всего: 15



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


--------------------
Открыта вакансия Junior Java Developer'а в нашем лондонском офисе, подробнее можно узнать здесь
PM MAIL MSN   Вверх
revenforv
Дата 1.9.2009, 16:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 47
Регистрация: 6.8.2009
Где: Санкт-Петербург

Репутация: нет
Всего: нет



Вообще-то тест несостоятелен по двум причинам:
- он искусственный;
- вы используете массив int, операции над которыми в jvm хорошо-оптимизированы.

И еще.. сравнивать if с switch - то же самое что сравнивать сладкое и длинное.
Как говорилось еще в альма-матер: switch - это искусственная конструкция, оптимизированная  для работы с целыми числами.
Как мне помнится, в Java Language Specification и Java VM specification придерживаются тех же принципов. Хотя, если есть желание - можете javap'нуть код и посмотреть на сгенеренные команды (и посчитать какой выигрыш в инструкциях будет - опять же, если есть желание и свободное время).

Это сообщение отредактировал(а) revenforv - 1.9.2009, 16:45
PM MAIL Skype   Вверх
Royan
Дата 1.9.2009, 17:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Dreamer
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 14.9.2002
Где: Лондон

Репутация: 3
Всего: 15



Цитата(revenforv @  1.9.2009,  13:44 Найти цитируемый пост)
Вообще-то тест несостоятелен по двум причинам:
- он искусственный;
- вы используете массив int, операции над которыми в jvm хорошо-оптимизированы.

Как бы вы его модифицировали, чтобы приблизить к реальным условиям? Вы же не будете спорить с тем, что операции if(){} else if(){} используются довольно часто. Цель данного теста проверить действительно ли switch может оказать быстрее чем if при прочих равных условиях.

Цитата(revenforv @  1.9.2009,  13:44 Найти цитируемый пост)
Как говорилось еще в альма-матер: switch - это искусственная конструкция, оптимизированная  для работы с целыми числами

В java switch работает в т.ч. с перечислениями можно попробовать переписать тест с enum'ами и сравнить, может быть к ночи ближе перепишу.



--------------------
Открыта вакансия Junior Java Developer'а в нашем лондонском офисе, подробнее можно узнать здесь
PM MAIL MSN   Вверх
revenforv
Дата 1.9.2009, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 47
Регистрация: 6.8.2009
Где: Санкт-Петербург

Репутация: нет
Всего: нет



 smile Да я то с вами полностью согласен, просто до сих пор помнится, как меня заставили на 3 курсе переписывать курсовую на C, в которой в for'е проверялось логическое условие, а не счетчик по массиву. Пришлось все for'ы переделывать в while. smile 

Ну это так - отступление от темы.. а вообще - я почитаю jls и скажу, что там написано на этот счет.

Это сообщение отредактировал(а) revenforv - 1.9.2009, 17:08
PM MAIL Skype   Вверх
COVD
Дата 1.9.2009, 17:07 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Цитата

Держу пари на 5 золотых, что никто не проверял это на практике 

Проиграете. Думаю, многие этим баловались. Я тоже когда-то экспериментировал. Теперь не заморачиваюсь ловлей блох и делаю как нагляднее. Есть ведь еще варианты. Например, в мап кладутся обьекты - екзекюторы. И осуществляется выбор нужного обьекта по ключу за один шаг. Разновидность этого подхода - положить экзекюторы в массив и извлекать по целочисленному индексу (в вашем эксперименте это temp). 
Выжимать 4% не очень благодарное занятие. Со временем убунту поменяется на шмубунту, выйдет новая версия java и все может быть наоборот. А для клиентских программ, бегающих в совершенно разных условиях, это еще более неопределенно. Ну и любой тюнинг производительности обычно идет в ущерб наглядности программы. Если количество пользователей системы возрастает и сервера не справляются, то масштабирование, подключение новых компьютеров, является более радикальным выходом.    

Это сообщение отредактировал(а) COVD - 1.9.2009, 17:43
PM MAIL   Вверх
fixxer
Дата 1.9.2009, 17:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 672
Регистрация: 14.9.2006
Где: Саратов, Россия

Репутация: 6
Всего: 27



Вообще некузяво бы еще версию java указывать

Код

java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)


Код

Core 2 Duo E4600 2.4GHz
Windows XP SP3


Код

DefinedIf,RandomIf,DefinedSw,RandomSw
1497,29,6815,50,1445,37,6813,20


Добавлено @ 17:43
Да еще, тест строго однопоточен - второе ядро вообще не задействовано было

Это сообщение отредактировал(а) fixxer - 1.9.2009, 17:44


--------------------
user posted image
PM MAIL ICQ   Вверх
LSD
Дата 1.9.2009, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(Royan @  1.9.2009,  15:19 Найти цитируемый пост)
Ну речь о разнице в 4,5% на моем примере. Положим, что в приложении данные конструкции используются в каком-нибудь высоконагруженном месте, тогда эти 4,5% весьма интересны

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




Цитата
java version "1.6.0_11"
Java™ SE Runtime Environment (build 1.6.0_11-b03)
Java HotSpot™ Client VM (build 11.0-b16, mixed mode, sharing)

DefinedIf,RandomIf,DefinedSw,RandomSw
1542,43,5806,48,1477,45,5810,01

Машина: Intel Xeon E5410 2.33 GHz, 2 GB RAM, Windows XP.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Royan
Дата 1.9.2009, 18:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Dreamer
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 14.9.2002
Где: Лондон

Репутация: 3
Всего: 15



Цитата(COVD @  1.9.2009,  14:07 Найти цитируемый пост)
Проиграете. Думаю, многие этим баловались. Я тоже когда-то экспериментировал. Теперь не заморачиваюсь ловлей блох и делаю как нагляднее. Есть ведь еще варианты. Например, в мап кладутся обьекты - екзекюторы. И осуществляется выбор нужного обьекта по ключу за один шаг. Разновидность этого подхода - положить экзекюторы в массив и извлекать по целочисленному индексу (в вашем эксперименте это temp).  

Понимаю. У меня желание написать тест родилось после того как я столкнулся в коде с необходимостью проверки внутреннего типа persistent cache'а. В зависимости от этого типа производилось то или иное действие. Тут нет проблемы что-то за экзекютить, к тому же для такой задачи больше подходит решение с ThreadPoolExecutor'ом


--------------------
Открыта вакансия Junior Java Developer'а в нашем лондонском офисе, подробнее можно узнать здесь
PM MAIL MSN   Вверх
COVD
Дата 1.9.2009, 18:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Цитата

Тут нет проблемы что-то за экзекютить, к тому же для такой задачи больше подходит решение с ThreadPoolExecutor'ом 

Экзекютор не в смысле задания, которое ставится в очередь и выполняется в отдельном потоке. Если внутри каждого if (или case) больше одной строчки кода, то может быть удобным оформить их методами разных обьектов (например, run() в анонимных Runnable ). Компактнее и возможно нагляднее будет выглядеть код. А выполняться все будет в том же потоке. 
Возможно, правильнее называть эти обьекты хэндлерами или процессорами.

Это сообщение отредактировал(а) COVD - 1.9.2009, 18:58
PM MAIL   Вверх
Galaran
Дата 1.9.2009, 20:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 91
Регистрация: 25.5.2009

Репутация: 1
Всего: 2



Код

Core 2 Duo E8500 3.16 GHz x 2

Ubuntu 9.04

java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Server VM (build 14.0-b16, mixed mode)


Код

DefinedIf,RandomIf,DefinedSw,RandomSw
1451,13,5815,59,1409,69,5938,24


Работало на одном ядре
PM MAIL   Вверх
fixxer
Дата 1.9.2009, 22:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 672
Регистрация: 14.9.2006
Где: Саратов, Россия

Репутация: 6
Всего: 27



Попробовал дома:

Код

java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)

Core 2 Duo E8400 3GHz
Ubuntu 8.04 LTS x86_64


Код

DefinedIf,RandomIf,DefinedSw,RandomSw
1022,68,2920,35,938,67,2906,47


 smile 





--------------------
user posted image
PM MAIL ICQ   Вверх
VSergeyV
Дата 2.9.2009, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 299
Регистрация: 9.5.2006
Где: Новосибирск

Репутация: нет
Всего: 3



Код

java version "1.5.0_10"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_10-b03)
Java HotSpot(TM) Client VM (build 1.5.0_10-b03, mixed mode, sharing)


OS: Windows Vista Business Service Pack 1
CPU: Intel Pentium D CPU 2.80GHz
     32-bit OS  
RAM: 2 GB


Код

DefinedIf,RandomIf,DefinedSw,RandomSw
2807,59,12140,73,2526,72,11460,62


Добавлено через 12 минут и 21 секунду
Код

java version "1.6.0_11"
Java(TM) SE Runtime Environment (build 1.6.0_11-b03)
Java HotSpot(TM) Client VM (build 11.0-b16, mixed mode, sharing)


OS: Windows Vista Business Service Pack 1
CPU: Intel Pentium D CPU 2.80GHz
     32-bit OS  
RAM: 2 GB


Код

DefinedIf,RandomIf,DefinedSw,RandomSw
2281,53,9380,82,2302,30,9377,77

PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1162 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.