【问题标题】:PHP Singleton class for all requests所有请求的 PHP Singleton 类
【发布时间】:2011-09-16 06:14:22
【问题描述】:

我有一个简单的问题。我使用 php 作为服务器部分并有一个 html 输出。我的站点显示有关其他服务器的状态。所以流程是:

  1. 浏览器用户继续访问 www.example.com/status
  2. 浏览器联系人 www.example.com/status
  3. PHP 服务器收到请求并在 www.statusserver.com/status 上请求状态
  4. PHP 接收数据,将其转换为可读的 HTML 输出并将其发送回客户端
  5. 浏览器用户可以看到状态。

现在,我在 php 中创建了一个单例类,它只需 8 秒即可访问状态服务器。所以它会在 8 秒内更新状态。如果用户请求更新,服务器会返回本地(在 www.example.com 上)存储的状态。

很好,不是吗?但后来我做了一个简单的测试并启动了 5 个浏览器窗口,看看它是否有效。到了这里,php 服务器为每个请求创建了一个单例类。所以现在有 5 个客户端在状态服务器上请求所有 8 秒的状态。这意味着我每 8 秒对状态服务器进行 5 次调用,而不是 1 次!

难道不能只为 apache 服务器中的所有用户提供一个实例吗?如果有 1000 个用户连接到 www.example.com/status....

,这将解决问题

感谢任何提示

============================== 编辑:

我已经在硬盘上使用了缓存:

public function getFile($filename)
{
    $diff = (time()-filemtime($filename));
    //echo "diff:$diff<br/>";
    if($diff>8){
        //echo 'grösser 8<br/>';
        self::updateFile($filename);
    }
    if (is_readable($filename)) {
        try {
            $returnValue = @ImageCreateFromPNG($filename);
            if($returnValue == ''){
                sleep(1);
                return self::getFile($filename);
            }else{
                return $returnValue;    
            }
        } catch (Exception $e){
            sleep(1);
            return self::getFile($filename);
        }
    } else {
        sleep(1);
        return self::getFile($filename);
    }
}

这是单例中的调用。我要求一个文件并将其保存在硬盘上。但所有请求同时调用它并开始请求状态服务器。

我认为唯一的解决方案是一个独立的应用程序,它每 8 秒对文件进行一次更新......所有请求都应该只读取文件并且不再能够更新它。 这个独立的可能是一个 perl 脚本或类似的东西......

【问题讨论】:

  • 所以现在你可以在实践中看到singleton it's anti-pattern.
  • 尝试使用this等应用服务器
  • 有趣的事情 arnaud.. 通常我不确定这是否适用于我的环境(我的供应商环境)。他们对朝这个方向发展的东西有一些限制……但我会看看它。欢呼

标签: php performance singleton


【解决方案1】:

php 请求由不同的进程处理,每个进程都有不同的状态,没有像其他 web 开发框架那样的常驻进程。您应该使用例如一些缓存直接在您的类中处理该行为。

查询服务器状态的方法应该有这个逻辑

public function getStatus() {
  if (!$status = $cache->load()) {
    // cache miss
    $status = // do your query here
    $cache->save($status); // store the result in cache
  }
  return $status;
}

这样,只有 X 的一个请求会获取真实状态。 X 值取决于您的缓存配置。

一些你可以使用的缓存库:

或者您可以将结果存储在纯文本文件中,并在每次请求时检查文件本身的m_time,如果超过 xx 秒,则重写它。

更新

您的代码很奇怪,为什么所有这些sleep 调用?为什么ImageCreateFromPNG 不抛出时会出现 try/catch 块?

您问的是不同的问题,因为 php 不是应用程序服务器,并且无法跨进程存储状态,因此您的方法是正确的。我建议您使用 APC(使用共享内存,因此它至少比读取文件快 10 倍)在不同进程之间共享状态。使用这种方法,您的代码可能会变成

public function getFile($filename)
{
    $latest_update = apc_fetch('latest_update');
    if (false == $latest_update) {
      // cache expired or first request
      apc_store('latest_update', time(), 8); // 8 is the ttl in seconds
      // fetch file here and save on local storage
      self::updateFile($filename);
    }
    // here you can process the file
    return $your_processed_file;
}

使用这种方法,如果一个进程在 if 行之后是 blocked,则 if 部分中的代码将从两个不同的进程执行,这不应该发生,因为 几乎 是原子操作.

此外,如果您想确保您应该使用 semaphores 之类的东西来处理这个问题,但对于这种要求来说,这将是一个过大的解决方案。

最后恕我直言,8 秒是一个小间隔,我会使用更大的间隔,至少 30 秒,但这取决于您的要求。

【讨论】:

  • 再次感谢法比奥。我来自 Java 世界,那里有很多不同的东西,所以我必须阅读很多内容。但这是今天的 IT,不是吗?一年前我有一个示例的代码,我只是维护我兄弟的网站。他有一个非常有趣的想法,这就是它的实现......但我们的供应商对此并不满意。一旦大量用户请求他的网站,他的网站就关闭了整个服务器范围。因此,我会同时阅读一些内容,非常感谢您提供一些新结果。干杯
【解决方案2】:

据我所知,这在 PHP 中是不可能的。但是,您当然可以序列化和缓存对象实例。
查看http://php.net/manual/en/language.oop5.serialization.php

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-15
    • 2023-03-30
    相关资源
    最近更新 更多