Nupraptorian
Nupraptorian

Reputation: 13

PHP - Slow performance on function return assignment

As part of a project i came across this situation where inside a loop, i store the value of a function return. This happened to be a bottleneck for the application, where big arrays would take forever to be processed.

To me, the assignment should be no reason for the incredible slow performance. On the other hand, the same function call, with no assign on return gives much better performance.

Can you explain me why the first loop is much slower?

Output: First took 1.750 sec. Second took 0.003 sec.

class one {

    private $var;

    public function __construct() {
         $this->var = array();
    }

    public function saveIteration($a) {     
        $this->var[] = $a;
        return $this->var;
    }

    public function getVar() {      
        return $this->var;      
    }
}

$one = new one();    
$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $res = $one->saveIteration($i);
}    
echo "First took " . number_format(microtime(true) - $time_start, 3) . " sec.";

$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $one->saveIteration($i);
}  

$res = $one->getVar();
echo "<br>Second took " . number_format(microtime(true) - $time_start, 3) . " sec.";

Upvotes: 0

Views: 1217

Answers (3)

ahmad
ahmad

Reputation: 2729

It probably have something to do with the fact that you're creating 10.000 arrays; each time incrementing the number of elements of the new array by 1 element.

My guess while you're inside the loop the local variable isn't freed on its own; Therefore I went ahead & tried freeing it using unset which got the results very close.

I know this is not a real world example; but in your code if you have something similar you could get away with it by just freeing (unsetting) the local variable once you're finished with it

here's your test code again:

class one {

    private $var;

    public function __construct() {
         $this->var = array();
    }

    public function saveIteration($a) {
        $this->var[] = $a;
        return $this->var;
    }

    public function getVar() {
        return $this->var;
    }
}

$one = new one();
$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $res = $one->saveIteration($i);
    unset($res);
}
echo "First took " . number_format(microtime(true) - $time_start, 3) . " sec.".PHP_EOL;

$time_start = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $one->saveIteration($i);
}

$res = $one->getVar();
echo "Second took " . number_format(microtime(true) - $time_start, 3) . " sec.".PHP_EOL;

Note: the only thing I've modify is adding unset in the first example

Result:

  • First took 0.068 sec.
  • Second took 0.062 sec.

Upvotes: 0

BeetleJuice
BeetleJuice

Reputation: 40886

@Jakumi made an excellent point. Since the values must be copied when you assign, 10,000 extra operations and a lot more memory are required in the first loop.

The difference between the two loops is actually much greater than your testing shows. Your comparison would be more fair if between the two tests, you reset with:

unset($one); $one = new one();

In your current test, the second loop is being executed while still holding the large array from the first loop in memory, so your results are not independent. See this modification

Upvotes: 0

Jakumi
Jakumi

Reputation: 8374

According to http://php.net/manual/en/functions.returning-values.php#99660 the array return value is not passed by-reference but by-value. Which means that a copy of the array is created (at the very least, when you change it again), which in turn needs time to actually create the copy (allocate memory, memcopy the data).

Upvotes: 1

Related Questions