The strange PHP reference efficiency problem analysis

  • 2020-05-16 06:27:49
  • OfStack

The function is as follows:
 
function update_timelist(&$arr,$timestamp,$threshold){ 
$timequeue = &$arr['timequeue']; 
while(!empty($timequeue[0])&&($timestamp-$timequeue[0])>$threshold){ 
array_shift($timequeue); 
} 
array_push($timequeue, $timestamp); 
if($arr['count']<count($timequeue)){ 
$arr['count'] = count($timequeue); 
} 
} 

Do you see anything wrong with this function? In fact, there is a big problem in the function:

$timequeue = &$arr['timequeue'];

It took nearly 40 seconds for the program to read in 22M data and generate a linked list of time nodes. The time to delete the line and use $arr['timequeue'] was shortened by 30 seconds, and it only took about 10 seconds to process 22M.
 
function update_timelist(&$arr,$timestamp,$threshold){ 
while(!empty($arr['timequeue'][0])&&($timestamp-$arr['timequeue'][0])>$threshold){ 
array_shift($arr['timequeue']); 
} 
array_push($arr['timequeue'], $timestamp); 
if($arr['count']<count($arr['timequeue'])){ 
$arr['count'] = count($arr['timequeue']); 
} 

Do you see what the problem is? The problem is the count function. The actual content space to which PHP points variables is marked for reference types and non-reference types, as shown in the following code:
 
$a = 'ofstack.com'; 
$b = $a; 
$c = $b; 

Only one copy of 'ofstack.com' will be copied when $b and $c are modified. In this case, the content space type of 'ofstack.com' is non-reference type. If you change it to the following code:
 
$a = 'ofstack.com'; 
$b = $a; 
$c = &$a; 

What's going to happen to this? Is it still 1 memory space for 'ofstack.com'? No, because $c is a reference to $a, and the storage space to which $a points needs to be marked as a reference type, then a separate copy of 'ofstack.com' must be made for $b, since $b points to a non-reference type.
We can understand that $c is now a reference to $a. If $b is still executing $a's space, then modifying $c will cause $b to change as well, so at this point, a copy of the reference must be made even if there is no write. It can also be understood that php points to only two types of memory space for variables: non-reference and reference. The two types cannot be mixed and transferred. If you need to change the state of the memory space somewhere, you need copy1.
Here's why an extra $timequeue = &$arr['timequeue'] causes count to slow down. Remember when the c function was called? In fact, the parameters we passed in need of a copy of copy1 and php as well, but copy on writing mechanism makes count not really copy when passing in a non-reference type, but $timequeue = &$arr['timequeue'] specifies the memory space of $timequeue as a reference type, while count ['timequeue'] requires a non-reference type, so count needs an copy1 copy of $arr['timequeue']. Directly pass $arr['timequeue'] why is there no problem? count of course USES the copy on writing mechanism, array_shift and array_push? They are incoming references, so don't worry about this not changing the $arr['timequeue'] type but actually passing in the 1 alias of $arr['timequeue'].

I have just started learning PHP, and the above analysis is not necessarily correct or comprehensive. You can email me on my home page.

Related articles: