嵌套 PHP 是不是包含 CPU/内存密集型?

Posted

技术标签:

【中文标题】嵌套 PHP 是不是包含 CPU/内存密集型?【英文标题】:Are nested PHP includes CPU/memory intensive?嵌套 PHP 是否包含 CPU/内存密集型? 【发布时间】:2012-03-05 16:30:41 【问题描述】:

我正在用 php 编写一个网站,并通过将所有请求定向到一个 index.php 文件(使用 .htaccess)来获取“漂亮的 url”(也隐藏了我的目录)。然后索引文件解析 uri 并包含请求的文件。这些文件中还包含多个包含,每个都可能打开一个 mysql 连接。然后 那些 文件也有包含,它们打开 sql 连接。它下降到大约 3-4 级。

此进程是否占用大量 CPU 和内存,包括 PHP 包含和打开(和关闭)每个包含文件中的 MySQL 连接?

另外,使用纯 htaccess 的漂亮 url 会使用更少的资源吗?

【问题讨论】:

【参考方案1】:

PHP 开销

将应用逻辑分解为源层次结构的答案取决于托管解决方案的方式。

如果您使用专用主机/VM,那么您可能会使用 mod_php+Xcache 或等效项,答案将是:不,它不会真正影响运行时,因为所有内容都在 PHP 操作码级别缓存在内存中。 如果您使用共享托管服务,那么它影响性能,因为任何 PHP 脚本都可能通过 PHP-cgi 加载,可能通过 suPHP 并且包含的​​整个源层次结构都需要读取并编译每个请求。更糟糕的是,在共享解决方案中,如果此请求是 1 分钟内的第一个请求,则服务器文件缓存将被刷新,并且编组此源将涉及大量物理 I/O = 秒时间延迟。

我管理了几个 phpBB 论坛,发现通过聚合共享主机实现的常见包含层次结构,我可以将用户响应时间减半。这里有一些文章更详细地描述了这一点 (Terry Ellison [phpBB])。并引用一篇文章:

让我用一些粗略的数字来量化我的观点。我需要强调的是,下面的数字是指示性的。我已将基准作为本文的附件包含在内,以防您想在自己的服务上验证它们。

20–40。如果文件系统缓存未准备好,则每秒可以打开和读取的文件数。 1,500–2,500。每秒可以打开和读取的文件数(如果文件系统缓存已使用其内容进行准备)。 300,000–400,000。 PHP 解释器每秒可以编译的行数。 20,000,000。 PHP 解释器每秒可以解释的 PHP 指令数。 500-1,000。 PHP 解释器每秒可以调用的 MySQL 语句数,如果数据库缓存已使用您的表内容进行准备。

有关更多信息,请参阅More on optimising PHP applications in a Webfusion shared service,您可以在其中复制基准测试以自己运行。

MySQL 连接

这里最简单的做法是连接连接。我使用我自己的 mysqli 类扩展,它使用标准的单对象每类模板。就我而言,任何模块都可以发出:

$db = AppDB::get();

返回这个对象。这很便宜,因为它是一个涉及六个 PHP 操作码的内部调用。

另一种传统的方法是使用全局来保存对象,然后只做一个

global $db;

在任何需要使用它的函数中。

小型应用程序的脚注

您建议将所有包含合并到一个包含文件中。这对于稳定的生产来说是可以的,但在测试期间是一个痛苦。我可以建议一个简单的妥协吗?将它们分开以进行测试,但允许加载单个复合材料。您分两部分执行此操作 (i) 我假设每个包含都定义了一个函数或类,因此为每个包含使用标准模板,例如

if( !function_exists( 'fred' ) ) 
    require "include/module1.php";

在主脚本中的任何加载之前,请执行以下操作:

@include "include/_all_modules.php";

这样,当您进行测试时,您会删除 _all_modules.php 并且脚本会退回到加载单个模块。当您高兴时,您可以重新创建_all_modules.php。您可以通过一个简单的“发布”脚本来完成这个服务器端,该脚本执行

system( 'cp include/[a-z]*.php include/_all_modules.php' );

这样,你可以两全其美

【讨论】:

感谢详细的回复!我在一个共享的环境中。尽管您链接到的文章看起来比我需要的信息多得多,但我从中得到的是我应该使用更少的包含,简化包含文件中的内容,并在整个请求期间使用一个连接。谢谢! Yves,在 MySQL 连接上 +1。我还添加了一个精简的建议,用于汇总您可能会感到满意的包含内容。 :-) 再次感谢特里。我一直在根据它们的功能将包含分离到文件中以便于调试,但是根据这里的建议,我正在考虑根据它们的使用频率重新排列它们。将所有常用方法放在一个文件中,将其他(并非在每个页面中使用的)方法放在一个或两个较小的文件中,以避免包含无论如何都不会使用的方法。【参考方案2】:

这取决于 MySQL 客户端代码,我知道在打开具有相同参数的 MySQL 连接时,连接通常会被重用。

我个人只会在前端控制器(你的 index.php 文件)中初始化数据库连接,因为无论如何一切都应该通过那里。

【讨论】:

这是一个很好的观点。通过.htaccess PHP 检查和解析以确定要包含的内容,您实际上是在两个不同的位置执行相同的工作两次。这将使您的代码更难维护。 谢谢。那么,我将在整个请求过程中只打开一个连接。【参考方案3】:

您可以使用include_once()require_once() 方法来确保PHP 只解析一次,从而节省处理时间。如果您怀疑您的代码可能会在每个脚本执行中多次尝试包含文件,这将特别有价值。

http://php.net/manual/en/function.include-once.php

我想使用 .htaccess 解析 URL 总是比任何其他方法使用更多的资源,纯粹是因为这些规则会在您的服务器遇到的每个 .php 文件请求时被激活。

【讨论】:

不完全是,如果您使用 -X 选项 strace apache2,那么您将看到处理 .htaccess 需要大约 2 毫秒。仅使用 <?php echo "hello world";?> 在共享托管服务(通常基于 suPHP)上需要大约 100 毫秒。 .htaccess 打开一个用户文件,而 PHP 通常打开几十个。

以上是关于嵌套 PHP 是不是包含 CPU/内存密集型?的主要内容,如果未能解决你的问题,请参考以下文章

C#:循环遍历嵌套结构的成员对象

嵌套包含失败

PHP代码和HTML代码的嵌套问题

我的 JSON 数据是不是应该包含嵌套字段而不是重复信息?

简单的嵌套视图是不是有效(如果不包含多余的表?)

Python字典嵌套(源码分析/自定义)