Форум программистов, компьютерный форум, киберфорум
Perl
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.64/14: Рейтинг темы: голосов - 14, средняя оценка - 4.64
52 / 37 / 9
Регистрация: 13.06.2019
Сообщений: 209

Какая альтернатива switch быстрее?

15.05.2020, 20:02. Показов 3050. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
что если требуется множественное ветвление алгоритма
причём имеется индекс ветви наподобие индекса массива

тогда конструкции типа switch оказываются не самыми эффективными
given-when, if-elsif начинают тормозить с ростом числа вариантов

обращение к элементу массива по индексу происходит без сравнений, при помощи вычисления позиции. с ростом числа вариантов выбор в массиве становится быстрее чем условный переход.
пример в подтверждение идеи
Perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!perl
 
=pod
 
Какой вариант переключения между многоими ветвями алгоритма самый 
быстрый
 
switch takes 8 s
if-elsif takes 5 s
predefined array takes 3 s
 
при малом числе ветвлений - if-elsif
 
=cut
 
use Modern::Perl;
use Time::Piece;
use Time::Seconds;
use constant (MAX => 10_000_000);
 
$|++;
 
my ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j) = 0;
my $t = localtime;
 
sub chkpoint($) {
    printf "$_[0] takes %d s\n", (localtime() - $t)->seconds;
    say "$a\t$b\t$c\t$d\t$e\t$f\t$g\t$h\t$i\t$j\n";
    ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j) = 0;
    $t = localtime;
}
 
 
{
no warnings;
for (0..MAX) {
    given (int rand 10) {
        when (0) {$a++}
        when (1) {$b++}
        when (2) {$c++}
        when (3) {$d++}
        when (4) {$e++}
        when (5) {$f++}
        when (6) {$g++}
        when (7) {$h++}
        when (8) {$i++}
        when (9) {$j++}
        default {die}
    }
}
}
chkpoint "switch";
 
 
for (0..MAX) {
    my $idx = int rand 10;
    if ($idx == 0) {$a++}
    elsif ($idx == 0) {$a++}
    elsif ($idx == 1) {$b++}
    elsif ($idx == 2) {$c++}
    elsif ($idx == 3) {$d++}
    elsif ($idx == 4) {$e++}
    elsif ($idx == 5) {$f++}
    elsif ($idx == 6) {$g++}
    elsif ($idx == 7) {$h++}
    elsif ($idx == 8) {$i++}
    elsif ($idx == 9) {$j++}
    else {die}
}
chkpoint "if-elsif";
 
 
my @a = (
    sub {$a++},
    sub {$b++},
    sub {$c++},
    sub {$d++},
    sub {$e++},
    sub {$f++},
    sub {$g++},
    sub {$h++},
    sub {$i++},
    sub {$j++},
);
for (0..MAX) {
    $a[int rand 10]->();
}
chkpoint "predefined array";

вот собственно хотел поделиться находкой.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.05.2020, 20:02
Ответы с готовыми решениями:

Mutator как альтернатива switch: оправдано ли
Вот два варианта Mutatora как альтернатива switch. class CMutator { public CMutator() { ...

if или switch? что быстрее
Здравствуйте. Подскажите пожалуйста,что быстрее будет выполняться много условий if ,или switch int z = 5; if (z==4) z= 3; if...

If или switch().case. Что быстрее
Есть два кода. Первый: if(a == 2) a += 2; if(a == 3) a+= 3; if(a == 4) a+=4; Второй:

3
Невнимательный
 Аватар для ft4l
3108 / 1285 / 358
Регистрация: 08.02.2013
Сообщений: 7,548
Записей в блоге: 2
17.05.2020, 02:39
попробовал уровнять им условия
Perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/usr/bin/perl
 
use strict;
use warnings;
no warnings 'experimental';
use v5.14;
use Benchmark 'cmpthese';
 
$|++;
my ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j) = (0,0,0,0,0,0,0,0,0,0);
my @arr = (0,1,2,3,4,5,6,7,8,9) x 10;
 
sub fgiven {
    for (@_) {
        given ($_) {
            when (0) {$a++}
            when (1) {$b++}
            when (2) {$c++}
            when (3) {$d++}
            when (4) {$e++}
            when (5) {$f++}
            when (6) {$g++}
            when (7) {$h++}
            when (8) {$i++}
            when (9) {$j++}
            default {die}
        }
    }
#   say join ' ', ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j);
    ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j) = (0,0,0,0,0,0,0,0,0,0)
}
 
sub fswitch {
    for (@_) {
        for  ($_) {
            $a++ when $_ == 0;
            $b++ when $_ == 1;
            $c++ when $_ == 2;
            $d++ when $_ == 3;
            $e++ when $_ == 4;
            $f++ when $_ == 5;
            $g++ when $_ == 6;
            $h++ when $_ == 7;
            $i++ when $_ == 8;
            $j++ when $_ == 9;
        }
    }
#   say join ' ', ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j);
    ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j) = (0,0,0,0,0,0,0,0,0,0)
}
 
sub fifelsif {
    for (@_) {
        if ($_ == 0) {$a++}
        elsif ($_ == 0) {$a++}
        elsif ($_ == 1) {$b++}
        elsif ($_ == 2) {$c++}
        elsif ($_ == 3) {$d++}
        elsif ($_ == 4) {$e++}
        elsif ($_ == 5) {$f++}
        elsif ($_ == 6) {$g++}
        elsif ($_ == 7) {$h++}
        elsif ($_ == 8) {$i++}
        elsif ($_ == 9) {$j++}
        else {die}
    }
#   say join ' ', ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j);
    ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j) = (0,0,0,0,0,0,0,0,0,0)
}
 
sub fsubsub {
    my @a = (
        sub {$a++},
        sub {$b++},
        sub {$c++},
        sub {$d++},
        sub {$e++},
        sub {$f++},
        sub {$g++},
        sub {$h++},
        sub {$i++},
        sub {$j++},
    );
    for (@_) {
        $a[$_]->();
    }
#   say join ' ', ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j);
    ($a, $b, $c, $d, $e, $f, $g, $h, $i, $j) = (0,0,0,0,0,0,0,0,0,0)
}
 
# fgiven @arr;
# fswitch @arr;
# fifelsif @arr;
# fsubsub @arr;
# say'';
# __END__
 
cmpthese( -1,
  {
    'fgiven' => sub { fgiven @arr},
    'fswitch' => sub { fswitch @arr},
    'fifelsif' => sub { fifelsif @arr},
    'fsubsub' => sub { fsubsub @arr },
  });
Code
1
2
3
4
5
6
root@zz:/home/zzz# ./btest.pl
            Rate   fgiven  fswitch  fsubsub fifelsif
fgiven   10326/s       --     -12%     -47%     -50%
fswitch  11712/s      13%       --     -39%     -43%
fsubsub  19355/s      87%      65%       --      -5%
fifelsif 20479/s      98%      75%       6%       --
на массиве из 100 чисел быстрее явно given

Добавлено через 14 минут
Наоборот хотел сказать )) быстрее if else elsif
0
52 / 37 / 9
Регистрация: 13.06.2019
Сообщений: 209
17.05.2020, 14:24  [ТС]
x_lab,
Модуль Benchmark прекрасен. Возьму на вооружение.

Мне кажется, и в моём варианте шансы были те же. Погрешность измерений, из-за того, что я использовал вероятностную функцию, была ничтожной. На моём компе каждая ветвь алгоритма выполнилась равное число раз ± 0.1%, в каждом из трёх вариантов.

Быть может на вашем компе, в силу особенностей кэширования, 10 ветвей алгоритма (не сто) - это не достаточно, чтобы множественные сравнения (в среднем 5 на каждый вызов всей конструкции с ветвлением по десяти "направлениям") оказались дороже, чем однократное вычисление позиции в массиве + вызов функции.

Предлагаю уровнять шансы так:
  1. выкинув rand - как вы и сделали
  2. добавив вызовы функций в каждую версию алгоритма
Тогда различия будут только в цене поиска нужной ветви.

... заминочка с proof-of-concept-примерчиком: захотелось сделать в общем виде по числу ветвей. И слегка завис..
NB
my $func, $var;
eval "$func=sub{ $var++ }"
$func->();
на досуге проверю - напишу
0
52 / 37 / 9
Регистрация: 13.06.2019
Сообщений: 209
22.05.2020, 20:00  [ТС]
6.pl
Perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!perl
 
=pod
 
1) Какая конструкция быстрее:
 
    for (0..N) {
        given ($_) {
            when (0) { branch0() }
            when (1) { branch1() }
            ...
        }
    }
 
    for (0..N) {
        for ($_) {
            branch0() when $_ == 0;
            branch1() when $_ == 1;
            ...
        }
    }
 
    for (0..N) {
        if ($_ == 0) { branch0() }
        elsif ($_ == 1) { branch1() }
        ...
    }
 
    # @branches = ( \branch0, \branch1 )
    for (0..N) {
        $branches[$_]->()
    }
 
2) Как число "ветвей" и характеристики железа (кэш, скорость ЦП) влияют на скорость?
 
3) Ф-ции предопределённые и внедрённые в контекст в результате "кодогенерации на ходу" работают с одинаковой скоростью?
 
 
 
 "Xeon E3 1235" 1.5 - 2.8 GHz, 8M + 4x256K
 BRANCHES   первая и последняя строка Benchmark*
                       Rate   for given    if array
  3         array 1186427/s  117%  103%   15%    --
                       Rate given   for    if array
  9         array  502758/s  321%  236%   94%    --
  100       array   51355/s 2322% 1504% 1020%    --
  100       array   76615/s 2849% 1875% 1265%    --
 
 "Athlon 64 X2 5200+" 2.7 GHz, 2x512K
 BRANCHES   первая и последняя строка Benchmark
                       Rate   for given    if array
  3         array  988320/s  134%  112%   29%    --
                       Rate given   for    if array
  9         array  409951/s  272%  259%  113%    --
  100       array   37996/s 2308% 1695% 1201%    --
 
* из первой строки видно как распределились "конкуренты", последний
самый быстрый; из последней строки видно процент преимущества данной
альтернативы по отношению к каждой из остальных;
см. https://metacpan.org/pod/Benchmark#cmpthese-(-COUNT,-CODEHASHREF,-%5B-STYLE-%5D-)
 
=cut
 
use strict;
use warnings;
use Benchmark 'cmpthese';
 
use feature qw'say switch';
no warnings "experimental::smartmatch";
 
use constant
    BRANCHES => 9;
 
my @branches;
 
# создание однотипных функций-ветвей алгоритма
# каждая функция
#   возвращает число предидущих её вызовов
#   является замыканием т.е. ??? создаёт отдельный экземпляр переменной-счётчика,
#     при выходе из контекста, где объявлен счётчик my $c
#   имя функции "внедряется" в ??? "глобальный контекст"
#     см. https://perldoc.perl.org/5.30.0/perlref.html#Function-Templates
for (0 .. BRANCHES - 1) {
    no strict 'refs';
    my $c = 0; # counter
    my $n = "branch$_"; # function name: branch0, branch1,...
 
    *$n = sub { $c++ };
 
    $branches[$_] = \&$n;
}
 
#say branch1() for 1..5; # теперь они существуют
#say branch2(); # 5 or 0 ? - у каждой свой счётчик
#__END__
 
# генерирует исходный код блоков для тестирования
# каждый блок включает
#   конструкцию вызова ветви по индексу и
#   цикл обеспечивающий однократный вызов каждой ветви
# параметры:
#   начальная строка
#   callback-функция для генерации кода вызова ветви
#   конечная строка
# возвращает ссылку на анонимную ф-цию
sub make_unit($$$) {
    my $s = shift;
    my $f = shift;
    $s .= "\n\t" . $f->() . "\n" for 0 .. BRANCHES - 1;
    $s .= shift;
    $s =<<END; 
sub {
  for (0 .. BRANCHES - 1) {
    $s } }
END
    $s =~ s/^\s*\n//gms; # пустые строки
    say $s;
    eval $s // die "making unit failed: $@";
}
 
cmpthese -1, {
    'given' => make_unit(
        'given ($_) {',
        sub { "when ($_) { branch$_() }" },
        '}'
    ),
    'for' => make_unit(
        'for ($_) {',
        sub { "branch$_() when \$_ == $_;" },
        '}'
    ),
    'if' => make_unit(
        '',
        sub { ($_ ? 'elsif' : 'if') . " (\$_ == $_) { branch$_() }" },
        ''
    ),
    'array' => make_unit(
        '$branches[$_]->()',
        sub {''},
        ''
    ),
};
 
 
#say join ', ', map {eval "branch$_()"} (0 .. BRANCHES - 1);
say "\nthe number of times every branch run - " . branch0();


здесь два способа "кодогенерации" налету. (кто-нибудь знает как это правильно называется?)
1. шаблон *$имя = \анонимная_ф_ция
2. $ф_ия = eval "sub {}"
похоже, мне так кажется, по скорости сгенерированные таким образом ф-ции не будут отличаться от определённых обычным порядком.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.05.2020, 20:00
Помогаю со студенческими работами здесь

Что быстрее switch(enum) или if else?
Может кто нибудь знает,какая конструкция лучше в плане производительности: 1) enum e{one, two, three}; switch (e) { case.. ...

Какая альтернатива есть
хочется сменить outlook на что то другое.Что посоветуете?

Какая альтернатива OpenGl?
Для курсового проекта в вузе надо написать простой кроссплатформенный 2d движок. До дедлайна не так много времени, поэтому изчуать OpenGl...

FULL JOIN.... какая альтернатива?
Искал ответ на этот же вопрос и получил ссылку на эту тему. to Михайло: а если просто, прежде чем что то советовать, попробовать...

Какая конструкция быстрее?
if a= 1 then else if a = 2 then else if a = 3 then (*или*) if a = 1 then if a = 2 then if a = 3 then Помню, что такой вопрос...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru