Почему переопределение функции происходит быстрее, чем вызов первого? - PullRequest
2 голосов
/ 27 января 2012

Я читаю файлы javascript в php и выполняю их, используя v8js.

Упрощенный пример:

$javascriptCode = file_get_contents($filename);
$funcName = 'func'.md5($filename);
$v8js->executeString("
 function {$funcName} () {
  {$javascriptCode}
 }");
$v8js->executeString("var testVariable = {$funcName}();");

~ 50 вызовов = 200 мс

Для повышения производительности я сократил последующие вызовы до вызова только имени функции, если функция уже была определена:

if ( !isset($this->cache[$filename]) ) {
 $javascriptCode = file_get_contents($filename);
 $funcName = 'func'.md5($filename);
 $v8js->executeString("
  function {$funcName} () {
   {$javascriptCode}
  }");
  $this->cache[$filename] = $funcName;
}
else {
 $funcName = $this->cache[$filename];
}
$v8js->executeString("var testVariable = {$funcName}();");

~ 50 вызовов = 900 мс

По некоторым причинам это медленнее, чем повторное выполнение определения функции (первая часть кода).

У меня есть несколько десятков javascript-файлов и функций, которые я вызываю, и все они работали в течение 200 мс, используя первый пример кода. После добавления кэширования для уже определенных имен функций и их повторного определения время выполнения для точно такого же кода составило около 900 мс.

Чтобы убедиться, что пропущенное переопределение является единственной причиной потери производительности, я изменил if:

if ( !isset($this->cache[$filename]) || true ) {

… сохраняя имя функции в массиве, исключая php-массив как возможную проблему.

Откуда происходит большая потеря производительности или как я могу отладить это дальше?

1 Ответ

1 голос
/ 27 января 2012

Я создал несколько тестов для дальнейшей идентификации и, наконец, нашел причину, скрытую глубоко в моем собственном коде JavaScript.

Даже при том, что код был идентичен, некоторые if в javascript решили отклониться и сделали все медленнее: -)

Вот исходный код моего последнего теста, который показал, что без переопределения он работает быстрее, чем ожидалось:

<?php
$runList = array(10, 100, 1000, 10000, 100000);
$jsFunc = 'function myTestFunc () { return {foo: "bar"}; } ';
foreach ($runList as $runs ) {

    $start = mstime();
    $js = new V8Js('Test');
    for ( $i = $runs; $i > 0; $i-- ) {
        $js->executeString($jsFunc, 'Test.Context');
        $js->executeString("myTestFunc();", 'Test.Context');
    }
    echo "#1: " . (mstime() - $start)." ({$runs} with re-definition)<br />";
    unset($js);

    $start = mstime();
    $js = new V8Js('Test');
    $js->executeString($jsFunc, 'Test.Context');
    for ( $i = $runs; $i > 0; $i-- ) {
        $js->executeString("myTestFunc();", 'Test.Context');
    }
    echo "#2: " . (mstime() - $start)." ({$runs} without re-definition)<br />";
    unset($js);
    echo "<hr />";
}

function mstime() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

Результаты:

#1: 0.000640869140625 (10 with re-definition)
#2: 0.0003800392150878906 (10 without re-definition)
#1: 0.001749992370605469 (100 with re-definition)
#2: 0.0009560585021972656 (100 without re-definition)
#1: 0.01554703712463379 (1000 with re-definition)
#2: 0.04881501197814941 (1000 without re-definition)
#1: 0.503957986831665 (10000 with re-definition)
#2: 0.1761679649353027 (10000 without re-definition)
#1: 4.813416957855225 (100000 with re-definition)
#2: 1.93553900718689 (100000 without re-definition)
...