不使用序列化在PHP中缓存对象

时间:2009-07-27 21:16:15

标签: php caching serialization

我有一个在PHP脚本中创建的复杂对象。我正在寻找一种方法来存储此对象,以便后续请求不必重新创建它,或花时间反序列化和重建它。使用xdebug我发现我花了整个请求时间的一半来构建这个对象。即使我将对象显式地存储在APC(或memcache)中,对它进行反序列化并加载所有类的时间几乎与创建对象的时间一样长。

我不知道是否可以在PHP中存储并稍后加载“已编译”的对象。这可能吗?还有其他解决方案吗?

我不确定这是可能的,但我想我应该问社区。

编辑:对象是二叉树,用作决策树。代码基本上是从树快速返回答案所需的API。这一切都需要以不断增长的速度执行,因此我尽可能地最大化性能。

9 个答案:

答案 0 :(得分:9)

据我所知,如果没有序列化,就不可能在PHP中缓存对象。但是,一般情况下,缓存机制(APC,Memcache等)实际上是在尝试删除数据库连接而不是提高性能(从而降低整体数据库应变)。这肯定是如何使用memcache等来处理Drupal。换句话说,缓存机制应该允许您扩展,尽管它们可能不会特别提高性能 实现缓存机制应该允许您更容易向外扩展,即使每台机器的性能对于单个连接而言并不比以前更好。在某个阈值时,数据库性能会急剧下降,缓存机制应该有助于缓解这个问题。

答案 1 :(得分:6)

查看Igbinary PHP扩展。它是序列化和反序列化的替代品,它可能适合您的需求。

它以二进制格式存储对象,而不是字符串,这会减少内存使用量,还会减少序列化和反序列化对象的时间。

虽然这确实经历了反序列化对象的过程,但二进制格式可能会提高性能,使此过程在您的应用程序中使用合理。

答案 2 :(得分:3)

也许解决方案是不构建单个,庞大且昂贵的对象。

鉴于PHP应用程序几乎从每个页面加载的干净平板开始,依赖于单个巨型对象的解决方案不适合该语言。因为你没有详细说明你的物品是什么&它做了什么,我无法确定,但我怀疑你并不真正需要对象在每个页面加载时所做的一切。如果是这种情况,您可能会认真考虑将其拆分为许多更小,更简单的类,您可以根据需要进行实例化。

答案 3 :(得分:2)

igBinary是一个有用的扩展,可以帮助您实现更快的序列化/反序列化过程。它用更聪明的二进制机制取代了标准的序列化机制。如果您管理自己的服务器并且可以安装它,那么值得一试。

答案 4 :(得分:1)

不,不能以非序列化形式存储PHP对象;至少,不是使用以下缓存解决方案(我已尝试过这些解决方案;不了解可能存在的其他解决方案)

  • 文件
  • 分布式缓存
  • APC
  • 数据库(是的,您可以考虑在DB中缓存内容^ ^ Drupal默认情况下会这样做)

如果需要花费很多时间来反序列化您的对象,那么它可能真的是吗?有什么办法可以减少它的大小吗?

例如,meybe你在那个对象中有很多HTML代码吗?如果是这样,它可以存储在另一个缓存条目中吗?
(序列化是“将一些数据转换为字符串;因此,如果您已经在使用字符串,则不需要重新序列化它以将其存储在缓存中” < / p>

或者从头开始创建它可能不需要太多时间?在这种情况下,缓存真的有必要吗?

答案 5 :(得分:1)

如果可能,在您的平台上编写一个简单的守护程序,在启动时加载您的树,然后通过套接字回答请求。您的服务器进程可以在不重新创建树的情况下分叉和回答查询。 编写一个守护进程并非易事,但记录得非常好(至少对C来说)。您可以使用pcntl和posix扩展将其转换为PHP。

答案 6 :(得分:0)

在这种情况下,更好的选择是编写自己的服务器。

它在php中很容易实现 - 你已经拥有了代码 - 但在编写服务器时,php可能不是大多数人的首选。

  • 它可能成为你的应用程序的新瓶颈(因为php不是真正的多线程就绪并且请求是连续回答的)
  • 并非所有主机都允许自定义cli脚本
  • 如果决策树发生更改,则必须通知服务器重建树

答案 7 :(得分:0)

虽然PHP可以为各种数据类型提供许多动态功能,但这些操作并不神奇,数据仍然存储为基本的本机数据类型,称为zval,在技术上是本机zend api中的复杂哈希表。与任何语言中的任何其他数据类型一样,每个zval仅存在一段有限的时间。对于PHP,此期间(最多)是处理HTTP请求的时间段。在任何情况下,为了使这些数据的持续时间长于单个请求,必须将其从原始zval转换为其他形式,然后以某种方式存储(这包括复杂类型,如PHP对象以及基本类型,如整数)。这将始终需要重新初始化每个zval,然后将数据从存储的表单转换回zval中的各种PHP数据类型。某些存储格式(如BSON)将比PHP序列化字符串更快,但(至少截至目前)这不会提供太多引人注意的性能跳转,因为它无法接近在多个请求中维护原始zval的性能。您仍然需要以某种方式序列化这些数据,经历存储它的时间,然后获取它,然后反序列化它。目前还没有真正的解决方案。

请注意,PHP可以说有三个不同的范围:SAPI,它启动并最终处理每个请求中的所有状态;扩展,在每个请求事件启动之前启动;然后是每个请求启动的脚本范围。所有PHP变量都在脚本范围内启动,但可以通过扩展和SAPI访问。但是,除了每个请求之外,唯一可以存在的范围是SAPI。换句话说,PHP对象只能在SAPI中的多个请求之间进行维护(此时扩展无法帮助解决此问题),因此只有自定义SAPI能够跨请求维护zval。

答案 8 :(得分:0)

您可以将应用程序重写为ReactPHP,在一个长时间运行的PHP进程中创建Web服务器(就像Node.js或Web.py一样)。然后,您可以将您的大对象构建一次(在服务器启动时)作为全局变量,并从请求事件处理程序访问它。

相关问题