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