PHP - 预加载全部 classes/functions
PHP - preload all classes/functions
有没有办法为 PHP 项目预加载(而不是自动加载)所有 classes/functions?
我正在考虑使用 PHPFastCGI 运行的 Web 应用程序(因此我们可以 bootstrap 它的一部分并在请求之间重用该位),并且使用作曲家(它的 class地图用于此目的?)。
这是一些背景信息:
"Regular" PHP 应用程序处理单个请求然后被杀死。预加载所有 classes/functions 意味着有更长的启动时间,仅自动加载用于请求的 classes 是一个聪明的优化,但它可以进一步改进(它们需要许多 "read filesystem" 操作很慢) ,通常通过将可能用于所有请求的 classes 分组到一个文件中(这就是 ClassPreloader 解决的问题)。
然而启动应用程序只处理一个请求然后终止它并不是唯一的选择:使用 PHP FastCGI 可以使应用程序在请求之间保持活动状态。这使我们能够将启动时间缩短 Request/Response 时间(例如,一次从 DIC 实例化所有服务)。
在分析我的应用程序时,我注意到自动加载总是出现在前 10 个最昂贵的独占函数调用中。在 PHP FastCGI 应用程序中,在启动阶段移动 class 加载以将其从 Request/Response 时间完全删除可能是有意义的。我正在尝试找出答案(我会做一些基准测试并发布结果)。
有关 运行 PHP 应用程序的这种 "exotic" 方式的更多信息,请参阅:
- 使用 ReactPHP 让您的应用保持活力:http://marcjschmidt.de/blog/2014/02/08/php-high-performance.html
- Fabien Potencier 谈论它:https://youtu.be/gpNbmEnRLBU
- 使用 PHPFastCGI 让 FastCGI(例如 php-fpm)管理 PHP 个进程:http://andrewcarteruk.github.io/slides/breaking-boundaries-with-fastcgi/
- 使用非阻塞 HTTP 应用程序 Aerys:http://blog.kelunik.com/2015/10/21/getting-started-with-aerys.html
- 使用原生 PHP 网络服务器 AppServer:http://www.sitepoint.com/appserver-a-production-ready-php-based-server/
不要。如果启用 opcache 则没有性能优势,并且还可能浪费内存(您并不总是需要加载所有 类)。
这是基准:https://phpixie.com/blog/benchmarking-autoloading-vs-combining-classes-into-a-single-file.html
如果您使用的是 composer,则 composer include 语句的 return 值将是此对象上 Composer\Autoload\ClassLoader. Calling the loadClass() 方法的一个实例,将包含 class 文件。因此,当您实际需要 class 时,PHP 已经知道它的定义,并且不需要调用作曲家向 'spl_autoload_register'.
注册的回调
<?php
/** @var Composer\Autoload\ClassLoader **/
$classLoader = include 'vendor/autoload.php';
$classLoader->loadClass('Path\To\MyClass');
$classLoader->loadClass('Path\To\OtherClass');
// ...
编辑:请注意,在您的场景中可能更有用的是预加载服务。实际上实例化您的应用程序所需的 classes 可能比让 PHP 读取它们的定义更昂贵。如何预加载服务将取决于您的依赖注入容器,但简单地 'getting' 服务将强制容器实例化它并记住它。
OP edit:这是实验,在 "empty" symfony 应用程序上用 ReactPHP.
完成
- 使用预加载 classes 的基准测试,损失 8% 的性能:https://github.com/gnugat-examples/bench-sf-standard/commit/c23d681cddc105b3a78f05679b2cffa84657f742
- 在预加载 classes 之上使用预加载服务的基准测试,与没有预加载的性能相同 classes/services:https://github.com/gnugat-examples/bench-sf-standard/commit/79a16cd3a7184aea6ed35461c4368dec32289ac9
因此结论令人惊讶,在启动服务器之前预热服务或 classes 不会带来性能提升。
事实证明,composer 有一个预包含文件的选项。参见doc。
从文档中复制:
{
"autoload": {
"files": ["src/preload.php"]
}
}
您可以 运行 必要的代码 startup/preload,在您的情况下使用:
class_exists(SomeClass1::class, TRUE);
class_exists(SomeClass2::class, TRUE);
这是强制自动加载 class 的技巧。
有没有办法为 PHP 项目预加载(而不是自动加载)所有 classes/functions?
我正在考虑使用 PHPFastCGI 运行的 Web 应用程序(因此我们可以 bootstrap 它的一部分并在请求之间重用该位),并且使用作曲家(它的 class地图用于此目的?)。
这是一些背景信息:
"Regular" PHP 应用程序处理单个请求然后被杀死。预加载所有 classes/functions 意味着有更长的启动时间,仅自动加载用于请求的 classes 是一个聪明的优化,但它可以进一步改进(它们需要许多 "read filesystem" 操作很慢) ,通常通过将可能用于所有请求的 classes 分组到一个文件中(这就是 ClassPreloader 解决的问题)。
然而启动应用程序只处理一个请求然后终止它并不是唯一的选择:使用 PHP FastCGI 可以使应用程序在请求之间保持活动状态。这使我们能够将启动时间缩短 Request/Response 时间(例如,一次从 DIC 实例化所有服务)。
在分析我的应用程序时,我注意到自动加载总是出现在前 10 个最昂贵的独占函数调用中。在 PHP FastCGI 应用程序中,在启动阶段移动 class 加载以将其从 Request/Response 时间完全删除可能是有意义的。我正在尝试找出答案(我会做一些基准测试并发布结果)。
有关 运行 PHP 应用程序的这种 "exotic" 方式的更多信息,请参阅:
- 使用 ReactPHP 让您的应用保持活力:http://marcjschmidt.de/blog/2014/02/08/php-high-performance.html
- Fabien Potencier 谈论它:https://youtu.be/gpNbmEnRLBU
- 使用 PHPFastCGI 让 FastCGI(例如 php-fpm)管理 PHP 个进程:http://andrewcarteruk.github.io/slides/breaking-boundaries-with-fastcgi/
- 使用非阻塞 HTTP 应用程序 Aerys:http://blog.kelunik.com/2015/10/21/getting-started-with-aerys.html
- 使用原生 PHP 网络服务器 AppServer:http://www.sitepoint.com/appserver-a-production-ready-php-based-server/
不要。如果启用 opcache 则没有性能优势,并且还可能浪费内存(您并不总是需要加载所有 类)。
这是基准:https://phpixie.com/blog/benchmarking-autoloading-vs-combining-classes-into-a-single-file.html
如果您使用的是 composer,则 composer include 语句的 return 值将是此对象上 Composer\Autoload\ClassLoader. Calling the loadClass() 方法的一个实例,将包含 class 文件。因此,当您实际需要 class 时,PHP 已经知道它的定义,并且不需要调用作曲家向 'spl_autoload_register'.
注册的回调<?php
/** @var Composer\Autoload\ClassLoader **/
$classLoader = include 'vendor/autoload.php';
$classLoader->loadClass('Path\To\MyClass');
$classLoader->loadClass('Path\To\OtherClass');
// ...
编辑:请注意,在您的场景中可能更有用的是预加载服务。实际上实例化您的应用程序所需的 classes 可能比让 PHP 读取它们的定义更昂贵。如何预加载服务将取决于您的依赖注入容器,但简单地 'getting' 服务将强制容器实例化它并记住它。
OP edit:这是实验,在 "empty" symfony 应用程序上用 ReactPHP.
完成- 使用预加载 classes 的基准测试,损失 8% 的性能:https://github.com/gnugat-examples/bench-sf-standard/commit/c23d681cddc105b3a78f05679b2cffa84657f742
- 在预加载 classes 之上使用预加载服务的基准测试,与没有预加载的性能相同 classes/services:https://github.com/gnugat-examples/bench-sf-standard/commit/79a16cd3a7184aea6ed35461c4368dec32289ac9
因此结论令人惊讶,在启动服务器之前预热服务或 classes 不会带来性能提升。
事实证明,composer 有一个预包含文件的选项。参见doc。 从文档中复制:
{
"autoload": {
"files": ["src/preload.php"]
}
}
您可以 运行 必要的代码 startup/preload,在您的情况下使用:
class_exists(SomeClass1::class, TRUE);
class_exists(SomeClass2::class, TRUE);
这是强制自动加载 class 的技巧。