【问题标题】:Cache Object in PHP without using serialize在 PHP 中缓存对象而不使用序列化
【发布时间】:2010-11-14 12:13:04
【问题描述】:

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

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

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

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

【问题讨论】:

  • 并不是说这是一种“不”序列化的方法。但可能想研究 __sleep() 和 __wakeup() 方法,以便它可以自动重建类。 us3.php.net/manual/en/…
  • @Chacha 感谢您提供的信息。我不确定这是一个解决方案,但我肯定从中学到了一些新东西!谢谢。
  • 根据定义,存储对象需要序列化。如果您确实需要重复、快速地访问内存中的大型二叉树,那么在每个请求上调用 PHP 脚本并不是正确的解决方案。
  • 你不能将大对象存储在APC中而不序列化它吗? php.net/manual/en/function.apc-store.php#73560
  • @rcourtana 当您将对象存储在 APC 中时,会调用内部序列化。如果您启动分析器并观看从 APC 执行此存储/检索,您会发现您花费大量时间进行序列化

标签: php caching serialization


【解决方案1】:

据我所知,如果不进行序列化,就不可能在 PHP 中缓存对象。然而,总的来说,缓存机制(APC、Memcache 等)实际上是在尝试移除数据库连接,而不是提高性能(从而减少整体数据库压力)。这绝对是 memcache 等人在 Drupal 中的使用方式。换句话说,缓存机制应该允许您进行扩展,尽管它们可能不会特别提高性能。
实施缓存机制应该可以让您更轻松地向外扩展,即使单台机器的性能并不比以前更好。在某个阈值下,数据库性能会急剧下降,缓存机制应该有助于缓解这个问题。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 从我对 Igbinary 的阅读来看,这似乎不一定会提高性能。我没有看到任何文档说明速度提高了,只是序列化对象的大小减小了。
    【解决方案3】:

    也许解决办法是不要建造一个单一的、巨大的、昂贵的物体。

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        • 文件
        • 内存缓存
        • APC
        • 数据库 (是的,你可以考虑在 DB 中缓存东西 ^^ Drupal 默认会这样做,例如)

        如果反序列化你的对象需要这么多时间,也许它真的是 ?有什么办法可以减小它的大小?

        例如,你可能在那个对象中有一大堆 HTML 代码?如果是这样,它可以存储在另一个缓存条目中吗?
        (序列化是将一些数据转换为字符串;因此,如果您已经在处理字符串,则无需重新序列化以将其存储在缓存中)

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

        【讨论】:

        • 顺便说一句,Wordpress 默认不缓存任何内容。所以,是的,您可以在数据库中缓存。
        • 该对象不存储任何额外的 html 或信息。问题表明从头开始创建非常昂贵,这就是“缓存”对象的全部目标。
        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          虽然 PHP 可以为各种数据类型提供很多动态特性,但这些操作并不神奇,并且数据仍然作为基本的原生数据类型存储在所谓的 zval 中,从技术上讲,zval 是原生 zend api 中的复杂哈希表。与任何语言中的任何其他数据类型一样,每个 zval 只会存在一段有限的时间。对于 PHP,此时间段(最多)是处理 HTTP 请求的时间段。在任何情况下,要使这些数据的持续时间超过单个请求,都必须将其从原始 zval 转换为其他形式,然后以某种方式存储(这包括 PHP 对象之类的复杂类型以及诸如 PHP 对象之类的基本类型)整数)。这总是需要重新初始化每个 zval,然后将数据从存储形式转换回 zval 中的各种 PHP 数据类型。一些存储格式(例如 BSON)将比 PHP 序列化字符串更快,但是(至少到目前为止)这不会提供太多明显的性能提升,因为它与跨多个请求维护原始 zval 的性能相去甚远。您仍然必须以某种方式序列化这些数据,经历存储它的时间,然后获取它,然后取消序列化它。目前还没有真正的解决方案。

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

          【讨论】:

            【解决方案8】:

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

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

            • 它可能会成为您应用程序的新瓶颈(因为 php 并没有真正支持多线程,并且请求是串行响应的)
            • 并非所有主机都允许自定义 cli 脚本
            • 如果你的决策树发生变化,你必须通知你的服务器重建决策树

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                猜你喜欢
                • 2018-03-29
                • 1970-01-01
                • 1970-01-01
                • 2011-04-22
                • 1970-01-01
                • 2014-10-15
                • 2014-12-30
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多