PHP缓存使用APC

3
假设我在一个PHP文件中使用PHP数组缓存数据,像这样:
/cache.php
<?php return (object) array(
    'key' => 'value',
);

我会像这样引入缓存文件:

<?php
$cache = include 'cache.php';

现在的问题是,缓存文件是否会被APC自动缓存在内存中?我的意思是,作为典型的opcode缓存,就像所有的.php文件一样。
如果我以不同的方式存储数据,例如JSON格式(cache.json),那么数据将不会被APC自动缓存? apc_store更快/更可取吗?
3个回答

10

不要将APC的缓存能力与其优化中间代码和缓存已编译代码的能力混淆。APC提供了两个不同的功能:

  1. 它提供了一种方便的缓存数据结构(对象、数组等)的方法,以便您可以使用apc_store和apc_fetch来存储/获取它们。
  2. 它保留您脚本的编译版本,以便下次运行时,它们可以更快地运行。

让我们看一个(1)的例子:假设您有一个需要1秒钟计算的数据结构:

function calculate_array() {
    sleep(1);
    return array('foo' => 'bar');
}
$data = calculate_array();
您可以将其输出存储,以便无需再次调用缓慢的calculate_array()函数:
function calculate_array() {
    sleep(1);
    return array('foo' => 'bar');
}
if (!apc_exists('key1')) {
    $data = calculate_array();
    apc_store('key1', $data);
} else {
    $data = apc_fetch('key1');
}

将会更加快速,远低于原来的1秒。

现在,对于上文中提到的(2):启用APC并不会使您的程序运行时间少于1秒,这是calculate_array()需要的时间。但是,如果您的文件还需要(比如说)100毫秒进行初始化和执行,仅仅启用APC就会使其需要大约20毫秒左右。因此,在初始化/准备方面增加了80%的时间,这在生产系统中可能会有很大的差异,所以即使您从未显式调用任何APC函数,简单地安装APC也可以对脚本的性能产生显着的积极影响。


所以cache.php会被编译成opcode?但是apc_store仍然更好更快吗? - jQguru
1
是的,file 将被操作码编译。apc_store 做的是不同的事情,它存储结构。这是两种不同的需求,需要分别处理。我会在我的答案中更新更多细节。 - periklis
3
我不喜欢第一句话:“APC不编译操作码,这是引擎的工作。”APC提供字节码(操作码/系统缓存),但它与变量缓存(用户缓存)不同。最终,除了第一个被扩展本身(隐式)使用,第二个被用户空间代码(显式)使用之外,它们的行为非常相似。附注:数据结构无法“计算”,它们只是存在。因此,您的示例也是误导性的。 - KingCrunch
在这种情况下,我相信apc_store会比将代码放入文件更快。 - periklis
@periklis 能提供一些数字吗 :) 我可以想象,使用 pro-apc_store 会有很大的差别,但我担心与单个 apc_fetch() 相比,对于单个文件来说可能无法测量... 不管怎样,这仍然是很有趣的。 - KingCrunch
显示剩余3条评论

2
如果您只是存储静态数据(就像您的示例一样),最好使用apc_store
这样做的原因不是操作码缓存是更快还是更慢,而是因为您正在使用include将静态数据获取到作用域中。
即使使用了操作码缓存,该文件仍将在每次执行时检查其一致性。PHP不必解析内容,但必须检查文件是否存在以及自操作码缓存创建以来是否已更改。即使只是对一个文件进行stat,文件系统检查也会消耗资源。
因此,在这两种方法中,我会使用apc_store来完全删除文件系统检查。

你可以通过http://php.net/apc.configuration.php#ini.apc.stat禁用`stat`调用。 - KingCrunch
1
这就是部署脚本存在的原因 ;) - KingCrunch
1
一个人仍然需要编写部署脚本,通常是同一个人忘记更改配置文件的人 :) - plasmid87
@Sven,有所不同。如果您没有明确使用apc_delete_file(),则必须清除服务器上的所有操作码缓存;而不仅仅是您已更新的文件。另一种选择是使用apc_clear_cache()(在不同的CGI实现中表现不同),或者希望重新启动服务器可以刷新它(再次强调,重新启动并不能完全保证缓存刷新,请查阅文档)。我的观点是,如果您必须使用apc_()函数来清除操作码缓存,为什么不消除潜在的故障点,一开始就使用apc_store()呢? - plasmid87
@KingCrunch 这是一个没有定论的问题,完全取决于服务器环境和需求。在重启快速且影响最小的较小安装中使用 stat=0 不是问题。不幸的是,在许多应用程序运行的大型安装中,通过重启清除整个缓存并不是一个非常吸引人的选择。我主要使用抽象驱动程序,它允许在不同环境中可互换地使用 APC、memcache 等。这限制了使用 include 获取缓存信息的开发优势,但当编写裸 PHP 时,我可以看到它的用例。 - plasmid87
显示剩余5条评论

1

与其他答案不同,我会使用数组文件解决方案(第一个)

<?php return (object) array(
    'key' => 'value',
);

原因在于,无论选择哪种解决方案,您都处于正确的一侧。但是,如果您将缓存交给APC自己处理,就不需要再使用apc_*()函数了。您只需包含并使用它即可。当您设置好后,就可以忘记它并专注于其他事情。
apc.stat = 0

你也可以避免在每个包含文件中使用 stat 调用。这对于生产环境非常有用,但请记得在每次部署时清除系统缓存。

http://php.net/apc.configuration.php#ini.apc.stat

哦,不要忘记:使用文件方法即使没有APC也可以工作。对于开发设置非常有用,通常不应使用任何缓存。


有趣,我没想到这比apc_fetch/apc_store更快。 - periklis
我也不认为它更快,但我认为差异非常微不足道 ;) - KingCrunch
我最初提出这个问题是因为我也认为差异微不足道,但使用文件:(1)您不需要编写额外的代码;(2)即使您没有APC,它仍然被缓存。 - jQguru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接