Welcome to MSDN Blogs Sign in | Join | Help

Гайдар Магдануров

Платформа и инструменты разработки, новости компании Microsoft и мысли об ИТ
Игры с производительностью if...else и switch в JavaScript

Решил немножко поиграть с JavaScript и тем, насколько методики по улучшению производительности работают в нем. Пробовать очевидные вещи вроде вычисляния выражений в условии цикла, приводящим к постоянным вычислениям одного и того же значения, или уменьшения повторений одинаковых выражений не интересно, поэтому я решил попробовать поиграть со switch вместо комбинаций if...else в разных браузерах (IE 7 и FireFox 2).

Для получения результатов тестов используем простой код (Test.html):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test Page</title>
    <script type="text/javascript">
    function TestCode()
    {
        // <code for testing goes here />
    }
    function Test()
    {
        var i = 0;
        var total = 0;
        for(i = 0; i < 10; i++)
        {
           var sTime = new Date();
           TestCode();
           var eTime = new Date(); 
           total += (eTime - sTime);
        }
        testResults.innerHTML = (total / 10) + " ms";
    }
    </script>
</head>
<body>
    <div>
        <p>
            <span id="testResults"></span>
        </p>
        <p>
            <input type="button" onclick="Test()" value="Test" />
        </p>
    </div>
</body>
</html>

Начнем с такого фрагмента, где используется последовательность if...else:

var test = 5;
var res = 0;
var i = 0;

for (i=0; i < 100000; i++)
{
if (test == 0) {res = test}
else if(test == 1) {res = test}
else if(test == 2) {res = test}
else if(test == 3) {res = test}
else if(test == 4) {res = test}
else if(test == 5) {res = test}
else if(test == 6) {res = test}
else if(test == 7) {res = test}
else if(test == 8) {res = test}
else if(test == 9) {res = test}
else if(test == 10) {res = test}
}

И сравним его с вот таким со switch:

var test = 5;
var res = 0;
var i = 0;

for(i = 0; i < 100000; i++)
{

switch (test) {
case 0 : res = test; break;
case 1 : res = test; break;
case 2 : res = test; break;
case 3 : res = test; break;
case 4 : res = test; break;
case 5 : res = test; break;
case 6 : res = test; break;
case 7 : res = test; break;
case 8 : res = test; break;
case 9 : res = test; break;
case 10 : res = test; break;
}

}

И со switch с переставленными случайно значениями:

var test = 5;
var res = 0;
var i = 0;

for(i = 0; i < 100000; i++)
{
switch (test) {
case 3 : res = test; break;
case 8 : res = test; break;
case 7 : res = test; break;
case 4 : res = test; break;
case 1 : res = test; break;
case 5 : res = test; break;
case 10 : res = test; break;
case 7 : res = test; break;
case 6 : res = test; break;
case 2 : res = test; break;
case 9 : res = test; break;
}
}

 

Вариант IE7.0.60001.18000 FireFox 2.0.0.14
if...else 46.7 ms 52.9 ms
switch 45.6 ms 13.8 ms
switch 2 45.6 ms 19.6 ms

Как видно из результатов, IE показывает стабильную производительность и не реагирует на оптимизации (и их кривизну :)). В то же время FireFox очень чувствителен к использованию switch вместо if. Теперь вот надо будет раскопать почему так происходит. Кто-нибудь может быть уже интересовался? ;)

Posted: Friday, April 25, 2008 3:49 PM by gaidar
Filed under: ,

Comments

zihotki said:

Подозреваю, что IE транслирует switch в последовательность условий, практически равнозначную тому, что мы получим, используя только if. FF же возможно использует для этого какой нибудь хеш/масив и это позволяет нам практически сразу же получить доступ к нужному методу.

# April 25, 2008 11:43 AM

Andrey Titov said:

Попробуй (можно на ты?) использовать для switch ключи с промежутками, в смысле не идущие подряд числа. Вероятно результат в FF станет таким же как для if'ов, если switch реализован как я предполагаю (как выбор по индексу из массива указателей переходов).

# April 30, 2008 4:03 PM

Andrey Titov [izobr] said:

И ещё - здесь тестируется скорость попадания в default. В реальности случаев попадания в определённый case скорее больше, чем в default.

# April 30, 2008 4:14 PM

Andrey Titov [izobr] said:

C default я i и test перепутал, извиняюсь.

First/Med/Last - соответственно первый/средний/последний case.

Первые три теста такие же.

Random Switch - по непоследовательным числам:

case 2 : res = test; break;

case 3 : res = test; break;

case 5 : res = test; break;

case 7 : res = test; break;

case 11 : res = test; break;

case 13 : res = test; break;

case 17 : res = test; break;

case 23 : res = test; break;

case 31 : res = test; break;

case 37 : res = test; break;

case 39 : res = test; break;

Random Unsorted Switch - непоследовательные неупорядоченные числа:

case 5 : res = test; break;

case 23 : res = test; break;

case 7 : res = test; break;

case 11 : res = test; break;

case 39 : res = test; break;

case 17 : res = test; break;

case 3 : res = test; break;

case 31 : res = test; break;

case 2 : res = test; break;

case 37 : res = test; break;

case 13 : res = test; break;

Random Reverse Switch - непоследовательные числа в реверсном порядке:

case 109 : res = test; break;

case 90 : res = test; break;

case 85 : res = test; break;

case 78 : res = test; break;

case 63 : res = test; break;

case 57 : res = test; break;

case 42 : res = test; break;

case 31 : res = test; break;

case 24 : res = test; break;

case 16 : res = test; break;

case 9 : res = test; break;

Opera:

Ifs First: 16 ms

Ifs Mid: 25 ms

Ifs Last: 41.6 ms

Sequential Switch First: 11.7 ms

Sequential Switch Mid: 25.6 ms

Sequential Switch Last: 35.9 ms

Unsorted Sequential Switch First: 9.9 ms

Unsorted Sequential Switch Mid: 24.4 ms

Unsorted Sequential Switch Last: 36.2 ms

Random Switch First: 10.1 ms

Random Switch Mid: 27.8 ms

Random Switch Last: 37.8 ms

Random Unsorted Switch First: 10.2 ms

Random Unsorted Switch Mid: 25.7 ms

Random Unsorted Switch Last: 36.8 ms

Random Reverse Switch First: 10.2 ms

Random Reverse Switch Mid: 26.1 ms

Random Reverse Switch Last: 37.1 ms

Firefox:

Ifs First: 20.2 ms

Ifs Mid: 49.3 ms

Ifs Last: 76.3 ms

Sequential Switch First: 14.7 ms

Sequential Switch Mid: 13.6 ms

Sequential Switch Last: 13.3 ms

Unsorted Sequential Switch First: 16.3 ms

Unsorted Sequential Switch Mid: 19.6 ms

Unsorted Sequential Switch Last: 23.9 ms

Random Switch First: 16.8 ms

Random Switch Mid: 20 ms

Random Switch Last: 24.1 ms

Random Unsorted Switch First: 16.8 ms

Random Unsorted Switch Mid: 19.1 ms

Random Unsorted Switch Last: 24 ms

Random Reverse Switch First: 16.4 ms

Random Reverse Switch Mid: 18.4 ms

Random Reverse Switch Last: 25.8 ms

В IE7 18 раз выскакивает сообщение "Сценарий на этой странице замедляет работу IE. Прервать?". Как это выключить не знаю - всё перепробовал.

Итого от распределения кейзов почти ничего не зависит - делается обычный if-else скан, только немного оптимизированнее написанного явно. Последние кейзы достигаются заметно медленнее первых.

# April 30, 2008 6:27 PM
New Comments to this post are disabled
Page view tracker