次の方法で共有


Игры с производительностью if...else и switch в JavaScript

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

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://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. Теперь вот надо будет раскопать почему так происходит. Кто-нибудь может быть уже интересовался? ;)

Comments

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

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

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

  • Anonymous
    April 30, 2008
    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 скан, только немного оптимизированнее написанного явно. Последние кейзы достигаются заметно медленнее первых.