Skip to content

Conversation

@h4kuna
Copy link
Contributor

@h4kuna h4kuna commented Sep 24, 2018

Hello
if I right measured, here is faster implementation for function array_key_last.

I move internal pointer of array.

Benchmark is on my gist.

Results on my machine.

array_key_first_symfony 0.0096850395202637 array_key_first 0.057085990905762 array_key_last_symfony 0.1387140750885 array_key_last 0.055586814880371 
@nicolas-grekas
Copy link
Member

The issue is that this mutates the internal pointer, which is something that shouldn't happen.

@h4kuna
Copy link
Contributor Author

h4kuna commented Sep 24, 2018

I extend the gist example. And look like a same behavior like a foreach. Unchanged internal pointer. I tested on php 5.4-7.2

EDIT Add reference for array to anonymous function, it is same results.

<?php function timer() { static $start; if ($start === null) { $start = microtime(true);	} else { $diff = microtime(true) - $start; $start = null; echo $diff . PHP_EOL;	} } function meassure(callable $callback, $message = '') { if ($message) { echo $message . PHP_EOL;	} timer(); for ($i = 0; $i < 100000; ++$i) { $callback();	} timer(); } function showKey(& $array) { echo key($array) . PHP_EOL; } function internalPointerToThirdPosition(& $array) { reset($array); next($array); next($array); } function array_key_first_symfony(array $array) { foreach ($array as $key => $value) { return $key; } } function array_key_first(array $array) { reset($array); return key($array); } function array_key_last_symfony(array $array) { $key = null; foreach ($array as $key => $value); return $key; } function array_key_last(array $array) { end($array); return key($array); } $array = ['foo' => null] + range(0, 100) + ['bar' => '1']; echo PHP_EOL; internalPointerToThirdPosition($array); showKey($array); meassure(function () use (&$array) { if (array_key_first_symfony($array) !== 'foo') { throw new \Exception('failed');	} }, 'array_key_first_symfony'); showKey($array); echo PHP_EOL; internalPointerToThirdPosition($array); showKey($array); meassure(function () use (&$array) { if (array_key_first($array) !== 'foo') { throw new \Exception('failed');	} }, 'array_key_first'); showKey($array); echo PHP_EOL; internalPointerToThirdPosition($array); showKey($array); meassure(function () use (&$array) { if (array_key_last_symfony($array) !== 'bar') { throw new \Exception('failed');	} }, 'array_key_last_symfony'); showKey($array); echo PHP_EOL; internalPointerToThirdPosition($array); showKey($array); meassure(function () use (&$array) { if (array_key_last($array) !== 'bar') { throw new \Exception('failed');	} }, 'array_key_last'); showKey($array);
@h4kuna
Copy link
Contributor Author

h4kuna commented Sep 24, 2018

This change internal pointer:

function array_key_last(array &$array) { end($array); return key($array); }
@nicolas-grekas
Copy link
Member

Indeed you're right sorry I read too fast.
In the original PR, there is a discussion about performance for small vs big arrays, what do you think about it?
See symfony/polyfill#133
(Note that this PR should be moved to this other main repository if we want to merge it.)

@h4kuna
Copy link
Contributor Author

h4kuna commented Sep 25, 2018

New implementation is every time the faster.

Here are results:

Array size: 10 array_key_last_symfony: 0.0030648708343506 array_key_last: 0.002047061920166 Array size: 20 array_key_last_symfony: 0.0038769245147705 array_key_last: 0.0020320415496826 Array size: 50 array_key_last_symfony: 0.0059189796447754 array_key_last: 0.0031149387359619 Array size: 100 array_key_last_symfony: 0.011098146438599 array_key_last: 0.0048739910125732 Array size: 200 array_key_last_symfony: 0.019550085067749 array_key_last: 0.0067110061645508 Array size: 500 array_key_last_symfony: 0.048456192016602 array_key_last: 0.019807100296021 Array size: 1000 array_key_last_symfony: 0.095025777816772 array_key_last: 0.040987968444824 Array size: 2000 array_key_last_symfony: 0.18471908569336 array_key_last: 0.079288959503174 Array size: 5000 array_key_last_symfony: 0.4891471862793 array_key_last: 0.20395493507385 Array size: 10000 array_key_last_symfony: 0.96754288673401 array_key_last: 0.4063241481781 

And benchmark code:

<?php function timer() { static $start; if ($start === null) { $start = microtime(true);	} else { $diff = microtime(true) - $start; $start = null; echo $diff . PHP_EOL;	} } function meassure(callable $callback, $message = '') { if ($message) { echo $message . ': ';	} timer(); for ($i = 0; $i < 10000; ++$i) { $callback();	} timer(); } function array_key_last_symfony(array $array) { $key = null; foreach ($array as $key => $value) {	;	} return $key; } function array_key_last(array $array) { end($array); return key($array); } $arraySize = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000]; foreach ($arraySize as $size) { echo PHP_EOL . PHP_EOL; $array = ['foo' => null] + range(0, $size) + ['bar' => '1']; echo sprintf('Array size: %s', $size) . PHP_EOL; meassure(function () use ($array) { if (array_key_last_symfony($array) !== 'bar') { throw new \Exception('failed');	}	}, 'array_key_last_symfony'); meassure(function () use ($array) { if (array_key_last($array) !== 'bar') { throw new \Exception('failed');	}	}, 'array_key_last'); }
@h4kuna
Copy link
Contributor Author

h4kuna commented Sep 25, 2018

Pull request moved to main repository

@h4kuna h4kuna closed this Sep 25, 2018
nicolas-grekas added a commit to symfony/polyfill that referenced this pull request Sep 30, 2018
This PR was merged into the 1.9-dev branch. Discussion ---------- array_key_last: improving performance First PR is [here](symfony/polyfill-php73#1), where was discussion. Q: The issue is that this mutates the internal pointer. A: created [benchmark](symfony/polyfill-php73#1 (comment)) and implementation does not change internal pointer. Q: about performance for small vs big arrays A: look like implementation is [every time faster](symfony/polyfill-php73#1 (comment)) This implementation is approx twice faster than cycle foreach. Benchmark is [on my gist](https://gist.github.com/h4kuna/6353ce99bd45b9c5fcdf49ef6d0e3da8). Results on my machine. ``` array_key_last_symfony 0.1387140750885 array_key_last 0.055586814880371 ``` Commits ------- 77aa2ff array_key_last: improving performance
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants