PHP Roundtable #38
Támogatónk:
-
Optimizing the performance of PHP apps
-
Instrumenting PHP applications
Mai témák
Optimizing the performance of PHP applications
sssss
ssss
ssss
Aspects of performance
Speed vs. Scalability
How to optimize perf?
Measure, Act, Measure
Tools for Measuring
-
AB, Loader.io
-
New Relic, Grafana
-
Blackfire, XHProf
-
PHPBench
-
VLD
What to optimize?
-
Database Access
-
Algorithms
-
Dependencies
-
PHP & Config
Database Access
Lazy-Load PDO
PDO starts the DB connection as soon as it is instantiated
N+1 Query Problem
<?php
$cities = City::get();
foreach ($cities as $city) {
$city->country->name;
}
N+1 Query Problem
<?php
$cities = City::with("country")->get();
Algorithms
Mind Time Complexity
Sign | Name | Good/Bad |
---|---|---|
O(1) | Constant Time | Perfect |
O(log n) | Logarithmic Time | Very good |
O(n) | Linear Time | Good |
O(n^2) | Quadratic Time | Avoid |
2^O(n) | Exponential Time | Panic |
Constant Time - O(1)
<?php
$numbers = [1, 2, 3, 4, 5];
echo $numbers[2];
Logarithmic Time - O(log n)
Binary Search
Linear Time - O(n)
<?php
$numbers = [1, 2, 3, 4, 5];
foreach ($numbers as $number) {
echo $number;
}
Quadratic Time - O(n^2)
<?php
$numbers1 = [1, 2, 3, 4, 5];
$numbers2 = [3, 4, 5, 6, 7];
foreach ($numbers1 as $i) {
foreach ($numbers2 as $j) {
if ($i === $j) {
echo $i;
}
}
}
Quadratic Time - O(n^2)
<?php
$numbers1 = [1, 2, 3, 4, 5];
$numbers2 = [3, 4, 5, 6, 7];
// [3 => 0, 4 => 1, 5 => 2, 6 => 3, 7 => 4]
$numbers2Map = array_flip($numbers2);
foreach ($numbers1 as $number) {
if (isset($numbers2Map[$number])) {
echo $number;
}
}
Quadratic Time - O(n^2)
<?php
$numbers1 = [1, 2, 3, 4, 5];
$numbers2 = [3, 4, 5, 6, 7];
// [3, 4, 5]
$numbers = array_intersect(
$numbers1,
$numbers2
);
foreach ($numbers as $number) {
echo $number;
}
Exponential Time - 2^O(n)
The Travelling Salesman Problem
Dependencies
Use a Fast Framework
<?php
$harmony = new Harmony(ServerRequestFactory::fromGlobals(), new Response());
$harmony
->addMiddleware(new HttpHandlerRunnerMiddleware(new SapiEmitter()))
->addMiddleware(new FastRouteMiddleware($router))
->addMiddleware(new DispatcherMiddleware())
->run();
Use a Fast Router
Use a Fast DI Container
PHP Configuration
Upgrade PHP
Upgrade PHP
PHP Engine overview
OPCache Tuning
[OPCACHE]
zend-extension=opcache
opcache.consistency_checks=0
opcache.enable=1
opcache.enable_cli=1
opcache.enable_file_override=1
opcache.fast_shutdown=1
opcache.max_accelerated_files=60000
opcache.memory_consumption=128
opcache.validate_timestamps=0
opcache.revalidate_freq=8
opcache.revalidate_path=0
opcache.save_comments=1
opcache.use_cwd=0
opcache.file_update_protection=0
opcache.interned_strings_buffer=32
Preloading
[OPCACHE]
...
opcache.preload=/var/www/preload.php
<?php
opcache_compile_file('/var/www/src/Class1.php');
opcache_compile_file('/var/www/src/Class2.php');
opcache_compile_file('/var/www/src/Class3.php');
// ...
PHP Micro-optimizations
Optimize autoloading
composer install \
--no-interaction \
--no-suggest \
--no-dev \
--no-scripts \
--prefer-dist \
--optimize-autoloader \
--classmap-authoritative
Optimize autoloading
<?php
// ------------ Slower ---------------
require_once("vendor/autoload.php");
// ------------ Faster ---------------
require_once("src/Class1.php");
Use these PHP 5.6 features
<?php
class Class1
{
public const $items = [
"Class1" => "/var/www" . "/src/Class1.php",
];
public static $items = [
"Class2" => __DIR__ . "/src/Class1.php",
];
}
-
constant expressions
-
interned strings
-
immutable arrays
Use these PHP 5.6 features
Omit types
<?php
// -------------------------------------- Slower ----------------------------------
function funct2(string $a, int $b, array $c, stdClass $d, float $e, bool $f): void
{
// ...
}
// -------------------------------------- Faster ----------------------------------
/**
* @param string $a
* @param int $b
* @param array $c
* @param stdClass $d
* @param float $e
* @param bool $f
* @return void
*/
function funct1($a, $b, $c, $d, $e, $f)
{
// ...
}
It's also a great way to tackle visual debt!
Omit types
Import functions
namespace App;
// ------- Slower ----------
count([]);
// ------- Faster ----------
\count();
use function count;
Import functions
Omit function calls
<?php
// ---------- Slower -------------
array_key_exists("key", $array);
// ---------- Faster -------------
isset($array["key"]);
Omit function calls
But...
Use arrays wisely
Use Closure binding
<?php
$kitchen = new Kitchen();
// ---------------------- Slower --------------------------
$sweetsThief = new ReflectionProperty("Kitchen", "yummy");
$sweetsThief->setAccessible(true);
// ---------------------- Faster --------------------------
$sweetsThief = Closure::bind(
static function (Kitchen $kitchen) {
return $kitchen->yummy;
},
null,
"Kitchen"
);
Use Closure binding
Conclusions
PHP 7+ itself is very fast
PHP 8 + JIT will be even faster
Usually I/O is the bottleneck
Measure!
Sometimes you just don't have to be fast
Thanks!
Sources
-
https://blog.professorbeekums.com/performance-vs-scalability/
-
https://blog.blackfire.io/speeding-up-autoloading-on-php-5-6-7-0-for-everyone.html
-
https://ocramius.github.io/blog/accessing-private-php-class-members-without-reflection/
-
https://steemit.com/php/@crell/php-use-associative-arrays-basically-never
Optimizing the Performance of PHP Applications
By Máté Kocsis
Optimizing the Performance of PHP Applications
- 739