Бавен ли е условният оператор?

Гледах някакъв код с огромен оператор switch и if-else оператор за всеки случай и моментално почувствах желание да оптимизирам. Както винаги трябва да прави един добър програмист, аз се заех да получа някои факти за трудни времена и започнах с три варианта:

  1. Оригиналният код изглежда така:

    public static bool SwitchIfElse(Key inKey, out char key, bool shift)
    {
        switch (inKey)
        {
           case Key.A: if (shift) { key = 'A'; } else { key = 'a'; } return true;
           case Key.B: if (shift) { key = 'B'; } else { key = 'b'; } return true;
           case Key.C: if (shift) { key = 'C'; } else { key = 'c'; } return true;
           ...
           case Key.Y: if (shift) { key = 'Y'; } else { key = 'y'; } return true;
           case Key.Z: if (shift) { key = 'Z'; } else { key = 'z'; } return true;
           ...
           //some more cases with special keys...
        }
        key = (char)0;
        return false;
    }
    
  2. Вторият вариант, преобразуван за използване на условния оператор:

    public static bool SwitchConditionalOperator(Key inKey, out char key, bool shift)
    {
        switch (inKey)
        {
           case Key.A: key = shift ? 'A' : 'a'; return true;
           case Key.B: key = shift ? 'B' : 'b'; return true;
           case Key.C: key = shift ? 'C' : 'c'; return true;
           ...
           case Key.Y: key = shift ? 'Y' : 'y'; return true;
           case Key.Z: key = shift ? 'Z' : 'z'; return true;
           ...
           //some more cases with special keys...
        }
        key = (char)0;
        return false;
    }
    
  3. Обрат с помощта на речник, предварително попълнен с двойки ключ/символ:

    public static bool DictionaryLookup(Key inKey, out char key, bool shift)
    {
        key = '\0';
        if (shift)
            return _upperKeys.TryGetValue(inKey, out key);
        else
            return _lowerKeys.TryGetValue(inKey, out key);
    }
    

Забележка: двата оператора за превключване имат абсолютно еднакви регистри и речниците имат еднакво количество знаци.

Очаквах, че 1) и 2) са донякъде подобни по отношение на производителността и че 3) ще бъде малко по-бавно.

За всеки метод, изпълняван два пъти по 10 000 000 итерации за загряване и след това време, за мое учудване получавам следните резултати:

  1. 0,0000166 милисекунди на повикване
  2. 0,0000779 милисекунди на повикване
  3. 0,0000413 милисекунди на повикване

Как е възможно това? Условният оператор е четири пъти по-бавен от изразите if-else и почти два пъти по-бавен от търсенето в речника. Пропускам ли нещо съществено тук или условният оператор е присъщо бавен?

Актуализация 1: Няколко думи за моя тестов сбруя. Изпълнявам следния (псевдо)код за всеки от горните варианти под Release компилиран .Net 3.5 проект във Visual Studio 2010. Оптимизацията на кода е включена и константите DEBUG/TRACE са изключени. Изпълнявам метода при измерване веднъж за загрявка, преди да направя измерване на времето. Методът run изпълни метода за голям брой итерации, като shift беше зададен както на true, така и на false и с избран набор от ключове за въвеждане:

Run(method);
var stopwatch = Stopwatch.StartNew();
Run(method);
stopwatch.Stop();
var measure = stopwatch.ElapsedMilliseconds / iterations;

Методът Run изглежда така:

for (int i = 0; i < iterations / 4; i++)
{
    method(Key.Space, key, true);
    method(Key.A, key, true);
    method(Key.Space, key, false);
    method(Key.A, key, false);
}

Актуализация 2: Задълбочавайки се, погледнах IL, генериран за 1) и 2) и открих, че структурите на главния превключвател са идентични, както бих очаквал, но корпусите на корпуса имат леки разлики. Ето IL, който гледам:

1) Изявление if/else:

L_0167: ldarg.2 
L_0168: brfalse.s L_0170

L_016a: ldarg.1 
L_016b: ldc.i4.s 0x42
L_016d: stind.i2 
L_016e: br.s L_0174

L_0170: ldarg.1 
L_0171: ldc.i4.s 0x62
L_0173: stind.i2 

L_0174: ldc.i4.1 
L_0175: ret 

2) Условният оператор:

L_0165: ldarg.1 
L_0166: ldarg.2 
L_0167: brtrue.s L_016d

L_0169: ldc.i4.s 0x62
L_016b: br.s L_016f

L_016d: ldc.i4.s 0x42
L_016f: stind.i2 

L_0170: ldc.i4.1 
L_0171: ret 

Някои наблюдения:

  • Условният оператор се разклонява, когато shift е равно на true, докато if/else се разклонява, когато shift е false.
  • Докато 1) всъщност се компилира до няколко повече инструкции от 2), броят на инструкциите, изпълнени, когато shift е вярно или невярно, е равен за двете.
  • Подреждането на инструкциите за 1) е такова, че само един слот за стека е зает през цялото време, докато 2) винаги зарежда два.

Някое от тези наблюдения предполага ли, че условният оператор ще работи по-бавно? Има ли други странични ефекти, които влизат в действие?


person Peter Lillevold    schedule 14.02.2010    source източник
comment
Имате предвид условния оператор, нали?   -  person Marc Gravell    schedule 14.02.2010
comment
Официално това е условният оператор, но често чувам да го наричат ​​троичен оператор. Доколкото знам, това е единственият оператор в C#, който приема три аргумента. Е, кой да се заяжда за номенклатура? :)   -  person Nathan    schedule 14.02.2010
comment
Не знам дали винаги трябва да го правя. Първият ми рефлекс би бил първо да погледна целевия код, за да се уверя, че 1/ и 2/ наистина са компилирани по различен начин. След това трябва ли да се грижите? Дори и да не са компилирани в същия ефективен код сега, може да са в следващата версия на вашия компилатор. Знанието, което се опитвате да придобиете, има в най-добрия случай временна стойност.   -  person Pascal Cuoq    schedule 14.02.2010
comment
Троичният оператор е просто оператор, който приема три аргумента ;-) en.wikipedia.org/wiki/Ternary_operation   -  person Eric J.    schedule 14.02.2010
comment
Нулираш ли хронометъра?? Имах подобен проблем преди. вижте stackoverflow.com/questions/ 2223248/   -  person ram    schedule 14.02.2010
comment
Изглежда, че и трите опции отнемат част от наносекунда. Сигурен съм, че изпотяването е огромна загуба на ценното ви време.   -  person ojrac    schedule 14.02.2010
comment
Съгласен съм с @ojrac, това звучи като абсурдно ранна предварителна оптимизация.   -  person Justin Johnson    schedule 14.02.2010
comment
@ojrac и @Justin - как можете, без да давам допълнителен контекст, да приемете, че това е ранна предварителна оптимизация и загуба на времето ми? Както и да е, тук получих много добри съвети и предложения, за да продължа, за да разбера какво причинява разликата в конструкциите 1) и 2).   -  person Peter Lillevold    schedule 14.02.2010
comment
Предполагам, че е загуба на време, защото работите с наносекунди, което е невероятно ниско ниво на оптимизация. Ако наистина трябва да обработвате проверки на ключове със скорост над 50 милиона в секунда, продължете да оптимизирате.   -  person ojrac    schedule 16.02.2010
comment
Все още не оптимизацията е централна тук. Въпросът е защо условният оператор може да бъде четири пъти по-бавен от обикновен оператор if/else и дори два пъти по-бавен от търсене в речник.   -  person Peter Lillevold    schedule 17.02.2010
comment
Използвахте произволен вход за всеки цикъл или константа? Ако е случайно, възможно е, колкото и да е малко вероятно, една от първите две опции да е получила лошо разтърсване. Търсенето в речника, колкото и да е бавно, трябва да е почти постоянно, докато други поне имат потенциал да бъдат доста дълги.   -  person Dustman    schedule 17.02.2010
comment
Напълно съгласен с @ojrac. Бих заложил големи суми пари, че това далеч не е истинско тясно място в кода. Ако този код ви причинява проблем с производителността, изглежда много вероятно, че има начин да го поправите, като просто не извиквате този код толкова често. Най-добрият начин за оптимизиране обикновено е да намерите начин изобщо да не вършите работата!   -  person kyoryu    schedule 22.02.2010
comment
И във всеки случай, ако трябва да се опитам да оптимизирам това, първото нещо, което бих направил, е да имам един оператор if в началото, който проверява дали shift е верен и след това преминава към два напълно отделни оператора switch.   -  person kyoryu    schedule 22.02.2010
comment
@Peter, често се озовавам в DEBUG/TRANCE. Радвам се, че не съм единственият. хаха   -  person Sky Sanders    schedule 22.02.2010
comment
@Sky - хаха! Благодаря, че посочи тази правописна грешка :)   -  person Peter Lillevold    schedule 22.02.2010
comment
@Kyoryu - да, това е, което всъщност правя в моя производствен код в момента. Все пак въпросът ми не е за това как най-добре да оптимизирам метода, а защо двата израза се изпълняват различно.   -  person Peter Lillevold    schedule 22.02.2010


Отговори (8)


Много странно, може би .NET оптимизацията има обратен ефект във вашия случай:

Авторът разглоби няколко версии на троични изрази и откри, че те са идентични с операторите if с една малка разлика. Тернарният оператор понякога създава код, който тества противоположното условие, което бихте очаквали, тъй като в него тества дали подизразът е фалшив, вместо да тества дали е вярно. Това пренарежда някои от инструкциите и понякога може да повиши производителността.

http://dotnetperls.com/ternary

Може да разгледате ToString на стойността enum (за неспециалните случаи):

string keyValue = inKey.ToString();
return shift ? keyValue : keyValue.ToLower();

РЕДАКТИРАНЕ:
Сравних метода if-else с троичния оператор и с 1000000 цикъла троичният оператор винаги е поне толкова бърз, колкото метода if-else (понякога с няколко милисекунди по-бърз , което подкрепя горния текст). Мисля, че сте направили някаква грешка при измерването на времето, което е отнело.

person Zyphrax    schedule 14.02.2010
comment
Направих някои тестове и в момента, в който добавите .ToString(), производителността спада. Операциите с низове са едни от най-бавните и ръчното тестване за изрични стойности и конвертирането, както в оригиналните примери, макар и по-подробно, е значително по-бързо. - person jrista; 14.02.2010
comment
Да, ToString() не е най-бързото решение, но би спестило много код. Ако производителността е проблем, отидете на ifs/оператора. - person Zyphrax; 14.02.2010
comment
Инспектирането на IL е нещо, върху което работя в момента. И да, също така очаквах да видя еднаква ефективност с if/else и условния оператор. Но наистина, ако спестяването на редове код беше крайната ми цел, тогава бих се спрял на речника си, той е чист и бърз и работи както за обикновени, така и за специални случаи без допълнителна логика. - person Peter Lillevold; 14.02.2010
comment
@Peter: Не съм сигурен как точно получавате показателите си за ефективност, но извадката от речника се представи около 400% ПО-БАВНО от другите две алтернативи в моето тестване. Разлика от половин секунда за if/троичен срещу почти 3 секунди за речник. Не бих заложил, че имплементацията на речника всъщност е много бърза, дори и да изглежда по-компактна. - person jrista; 15.02.2010
comment
@Zyphrax - вижте актуализирания ми въпрос. Всъщност изглежда, че if/else тества обратното условие. Може ли тази разлика да доведе до повишаване на производителността за if/else вместо условния оператор? - person Peter Lillevold; 22.02.2010
comment
@Peter: може да има малка разлика, в някакъв момент (много нива на абстракция, по-дълбоки от c#) всичко се свежда до това колко пъти се осъществява достъп до паметта, колко цикъла на процесора са необходими за обработка на вашето (оптимизирано) изявление и т.н. ... и т.н.. Но ние говорим за разлика от няколко милисекунди. над един милион цикъла. Направете тези няколко милисекунди. наистина ли има толкова голямо значение? - person Zyphrax; 22.02.2010

Ще ми е любопитно да знам дали тествате това с компилация за отстраняване на грешки или версия. Ако това е компилация за отстраняване на грешки, тогава разликата вероятно може да се дължи на ЛИПСАТА на оптимизации на ниско ниво, които компилаторът добавя, когато използвате режим на издаване (или ръчно деактивирайте режима на отстраняване на грешки и активирайте оптимизациите на компилатора.)

Бих очаквал обаче с включени оптимизации троичният оператор да е или със същата скорост, или малко по-бърз от оператора if/else, докато търсенето в речника е най-бавно. Ето моите резултати, 10 милиона итерации за загряване, последвани от 10 милиона времеви, за всяка:

РЕЖИМ НА ОТСТРАНЯВАНЕ НА ГРЕШКИ

   If/Else: 00:00:00.7211259
   Ternary: 00:00:00.7923924
Dictionary: 00:00:02.3319567

РЕЖИМ НА ОСВОБОЖДАВАНЕ

   If/Else: 00:00:00.5217478
   Ternary: 00:00:00.5050474
Dictionary: 00:00:02.7389423

Мисля, че тук е интересно да се отбележи, че преди да бъдат активирани оптимизациите, троичното изчисление беше по-бавно от if/else, докато след това беше по-бързо.

РЕДАКТИРАНЕ:

След малко повече тестове, в практически смисъл, има малка или никаква разлика между if/else и троичен. Докато троичният код води до по-малък IL, те работят почти еднакво един с друг. В дузина различни тестове с двоичен режим на освобождаване резултатите от if/else и троичния бяха или идентични, или отклонени с част от милисекунда за 10 000 000 итерации. Понякога if/else беше малко по-бързо, понякога ternary беше, но на практика те изпълняват същото.

От друга страна, речникът се представя значително по-зле. Що се отнася до тези видове оптимизации, не бих си губил времето да избирам между if/else и троичен код, ако кодът вече съществува. Въпреки това, ако в момента имате имплементация на речник, определено бих го преработил, за да използвам по-ефективен подход и да подобря ефективността ви с около 400% (все пак за дадената функция.)

person jrista    schedule 14.02.2010
comment
Любопитно ми е как изграждате своя примерен речник. Вашите числа тук изобщо не се сравняват с моите. Какъв тип използвате за търсене? - person Peter Lillevold; 15.02.2010
comment
Копирах и поставих вашия код... той е идентичен. Моите времена са за всичките 10 милиона итерации, нито за една заявка (разделителната способност на хронометъра започва да става неточна, когато говорите за няколко наносекунди, така че намирам измерването на целия процес за по-ефективен тест.) - person jrista; 15.02.2010
comment
Отчитате ли инициализиране на вашия речник в рамките на времето на речника? Аз не. И да, също така изпълнявам режим на освобождаване с оптимизации. - person Peter Lillevold; 22.02.2010
comment
@Peter: Не, речникът се инициализира преди времеизмерването. Ще ми е любопитно да видя вашето внедряване... ако успея да накарам речника си да се доближи до вашия, това би било чудесно. Никога не съм виждал .NET речници да работят толкова добре. - person jrista; 24.02.2010
comment
@Peter: Да, това е същият код, който имам, тъй като копирах тази част. Имах предвид кода, който всъщност прави времето и измерването. Измерих времето, необходимо за завършване на всички 10 милиона итерации като част. Може би това причинява някаква разлика между вашето измерване и моето. - person jrista; 24.02.2010
comment
@Peter: Благодаря! Когато се прибера вкъщи, ще опитам още малко тестове и ще видя какви числа ще получа. - person jrista; 24.02.2010

Интересно, отидох и разработих малък клас IfElseTernaryTest тук, добре, кодът не е наистина „оптимизиран“ или добър пример, но въпреки това... в името на дискусията:

public class IfElseTernaryTest
{
    private bool bigX;
    public void RunIfElse()
    {
        int x = 4; int y = 5;
        if (x &gt; y) bigX = false;
        else if (x &lt; y) bigX = true; 
    }
    public void RunTernary()
    {
        int x = 4; int y = 5;
        bigX = (x &gt; y) ? false : ((x &lt; y) ? true : false);
    }
}

Това беше IL изхвърлянето на кода...интересното беше, че троичните инструкции в IL всъщност бяха по-кратки от if....

.class /*02000003*/ public auto ansi beforefieldinit ConTern.IfElseTernaryTest
       extends [mscorlib/*23000001*/]System.Object/*01000001*/
{
  .field /*04000001*/ private bool bigX
  .method /*06000003*/ public hidebysig instance void 
          RunIfElse() cil managed
  // SIG: 20 00 01
  {
    // Method begins at RVA 0x205c
    // Code size       44 (0x2c)
    .maxstack  2
    .locals /*11000001*/ init ([0] int32 x,
             [1] int32 y,
             [2] bool CS$4$0000)
    .line 19,19 : 9,10 ''
//000013:     }
//000014: 
//000015:     public class IfElseTernaryTest
//000016:     {
//000017:         private bool bigX;
//000018:         public void RunIfElse()
//000019:         {
    IL_0000:  /* 00   |                  */ nop
    .line 20,20 : 13,23 ''
//000020:             int x = 4; int y = 5;
    IL_0001:  /* 1A   |                  */ ldc.i4.4
    IL_0002:  /* 0A   |                  */ stloc.0
    .line 20,20 : 24,34 ''
    IL_0003:  /* 1B   |                  */ ldc.i4.5
    IL_0004:  /* 0B   |                  */ stloc.1
    .line 21,21 : 13,23 ''
//000021:             if (x &gt; y) bigX = false;
    IL_0005:  /* 06   |                  */ ldloc.0
    IL_0006:  /* 07   |                  */ ldloc.1
    IL_0007:  /* FE02 |                  */ cgt
    IL_0009:  /* 16   |                  */ ldc.i4.0
    IL_000a:  /* FE01 |                  */ ceq
    IL_000c:  /* 0C   |                  */ stloc.2
    IL_000d:  /* 08   |                  */ ldloc.2
    IL_000e:  /* 2D   | 09               */ brtrue.s   IL_0019

    .line 21,21 : 24,37 ''
    IL_0010:  /* 02   |                  */ ldarg.0
    IL_0011:  /* 16   |                  */ ldc.i4.0
    IL_0012:  /* 7D   | (04)000001       */ stfld      bool ConTern.IfElseTernaryTest/*02000003*/::bigX /* 04000001 */
    IL_0017:  /* 2B   | 12               */ br.s       IL_002b

    .line 22,22 : 18,28 ''
//000022:             else if (x &lt; y) bigX = true; 
    IL_0019:  /* 06   |                  */ ldloc.0
    IL_001a:  /* 07   |                  */ ldloc.1
    IL_001b:  /* FE04 |                  */ clt
    IL_001d:  /* 16   |                  */ ldc.i4.0
    IL_001e:  /* FE01 |                  */ ceq
    IL_0020:  /* 0C   |                  */ stloc.2
    IL_0021:  /* 08   |                  */ ldloc.2
    IL_0022:  /* 2D   | 07               */ brtrue.s   IL_002b

    .line 22,22 : 29,41 ''
    IL_0024:  /* 02   |                  */ ldarg.0
    IL_0025:  /* 17   |                  */ ldc.i4.1
    IL_0026:  /* 7D   | (04)000001       */ stfld      bool ConTern.IfElseTernaryTest/*02000003*/::bigX /* 04000001 */
    .line 23,23 : 9,10 ''
//000023:         }
    IL_002b:  /* 2A   |                  */ ret
  } // end of method IfElseTernaryTest::RunIfElse

  .method /*06000004*/ public hidebysig instance void 
          RunTernary() cil managed
  // SIG: 20 00 01
  {
    // Method begins at RVA 0x2094
    // Code size       27 (0x1b)
    .maxstack  3
    .locals /*11000002*/ init ([0] int32 x,
             [1] int32 y)
    .line 25,25 : 9,10 ''
//000024:         public void RunTernary()
//000025:         {
    IL_0000:  /* 00   |                  */ nop
    .line 26,26 : 13,23 ''
//000026:             int x = 4; int y = 5;
    IL_0001:  /* 1A   |                  */ ldc.i4.4
    IL_0002:  /* 0A   |                  */ stloc.0
    .line 26,26 : 24,34 ''
    IL_0003:  /* 1B   |                  */ ldc.i4.5
    IL_0004:  /* 0B   |                  */ stloc.1
    .line 27,27 : 13,63 ''
//000027:             bigX = (x &gt; y) ? false : ((x &lt; y) ? true : false);
    IL_0005:  /* 02   |                  */ ldarg.0
    IL_0006:  /* 06   |                  */ ldloc.0
    IL_0007:  /* 07   |                  */ ldloc.1
    IL_0008:  /* 30   | 0A               */ bgt.s      IL_0014

    IL_000a:  /* 06   |                  */ ldloc.0
    IL_000b:  /* 07   |                  */ ldloc.1
    IL_000c:  /* 32   | 03               */ blt.s      IL_0011

    IL_000e:  /* 16   |                  */ ldc.i4.0
    IL_000f:  /* 2B   | 01               */ br.s       IL_0012

    IL_0011:  /* 17   |                  */ ldc.i4.1
    IL_0012:  /* 2B   | 01               */ br.s       IL_0015

    IL_0014:  /* 16   |                  */ ldc.i4.0
    IL_0015:  /* 7D   | (04)000001       */ stfld      bool ConTern.IfElseTernaryTest/*02000003*/::bigX /* 04000001 */
    .line 28,28 : 9,10 ''
//000028:         }
    IL_001a:  /* 2A   |                  */ ret
  } // end of method IfElseTernaryTest::RunTernary

Така че изглежда, че този троичен оператор е очевидно по-кратък и бих предположил, че по-бърз, тъй като се използват по-малко инструкции... но на тази основа изглежда противоречи на вашия случай #2, което е изненадващо...

Редактиране: След коментара на Скай, предлагащ „раздуване на кода за #2“, това ще опровергае казаното от Скай!!! Добре, кодът е различен, контекстът е различен, това е примерно упражнение за проверка на IL дъмпа, за да видите...

person t0mm13b    schedule 14.02.2010
comment
„Подозирах“ и може да си прав, но примерът ти не доказва това. Това само доказва, че кодът за израза, който компилирахте, оптимизира по-малки. Лесно е да се компилира дадения код и действително да се покаже доказателство.... - person Sky Sanders; 14.02.2010

Бих очаквал #1 и #2 да са еднакви. Оптимизаторът трябва да доведе до същия код. Очаква се речникът в #3 да е бавен, освен ако не е оптимизиран по някакъв начин, за да не използва действително хеш.

Когато кодирахме системи в реално време, ние винаги използвахме справочна таблица - прост масив - за превод, както е дадено във вашия пример. Най-бързо е, когато диапазонът на въвеждане е сравнително малък.

person Doug Domeny    schedule 14.02.2010
comment
Не разбирам защо сте гласувани против. OP е разбрал погрешно колко бързи трябва да бъдат търсенията в речника и вие го изяснявате. - person Noon Silk; 14.02.2010
comment
@silky, Благодаря! И аз не знам защо ме отхвърлиха. Те не оставиха коментар. - person Doug Domeny; 14.02.2010
comment
Сериозно. Знам какво да очаквам от извадката от речника. Ясно заявявам, че очаквам да е по-бавно. Целият ми въпрос произтича от факта, че моята извадка от условен оператор беше много по-бавна от if/else И от речника. Справочна таблица е добро предложение и бих могъл да добавя проба въз основа на това към моето тестово легло. - person Peter Lillevold; 14.02.2010

Не разбирам съвсем защо бихте очаквали оператор if да бъде по-бавен от търсенето в речника. Най-малкото трябва да се изчисли хешкод и след това да се търси в списък. Не виждам защо бихте предположили, че това е по-бързо от cmp/jmp.

По-конкретно, дори не мисля, че методът, който оптимизирате, е толкова страхотен; изглежда, че може да се подобри на етапа на извикване (въпреки че не мога да съм сигурен, тъй като не сте предоставили контекста).

person Noon Silk    schedule 14.02.2010
comment
Не очаквах if/else NOR условното условие да бъде по-бавно от речник, заявих, че очаквам търсенето в речника да бъде по-бавно. Причината за включването на извадка от речник на първо място беше просто да има някаква основа за сравнение. - person Peter Lillevold; 14.02.2010

Ако приемем, че сте загрижени за производителността на този метод (и ако не сте, защо си правите труда да го публикувате?), трябва да обмислите съхраняването на char стойностите в масив и преобразуването на Key стойностите в индекс в масива.

person Robert Rossney    schedule 14.02.2010
comment
Загрижен съм за ефективността на метода и за тази цел мога да го оптимизирам до приемлива мярка. Това обаче не е въпросът, въпросът е защо условният оператор се представя по-лошо от еквивалентен оператор if-else. - person Peter Lillevold; 22.02.2010
comment
Ако 50% от текста на вашия въпрос не е свързан с въпроса, на който искате да получите отговор, наистина няма да навреди да го пропуснете. - person Robert Rossney; 22.02.2010

Нямам VS под ръка, но със сигурност има прост вграден начин да получа ключа като символ? Нещо като метод toString, така че можете да замените този чудовищен switch с това:

if (shift)
  return inKey.toString().toUppercase();
else
  return inKey.toString().toLowercase();
person DisgruntledGoat    schedule 17.02.2010
comment
...което би направило кода хубав и прост, но напълно би съсипало производителността. Нито едно от тях обаче не е фокусът на въпроса ми, търся причината, поради която условният оператор работи по-бавно от оператора if/else. - person Peter Lillevold; 22.02.2010
comment
Наистина ли ще развали производителността? Тествали ли сте нещо подобно на кода, който публикувах? Разбира се, може да е малко по-бавно, но само няколко ms в голямата схема на нещата. - person DisgruntledGoat; 22.02.2010

Бих избрал третия вариант само защото е по-четлив/поддържан. Обзалагам се, че този код не е тясното място за ефективността на вашето приложение.

person Jader Dias    schedule 14.02.2010
comment
Това не отговаря на въпроса. Въпросът не беше коя версия трябва да бъде избрана, въпросът е опит да се стигне до основната причина за неочакван резултат. - person Nathan; 14.02.2010