【问题标题】:Single instance of a web page网页的单个实例
【发布时间】:2010-08-02 12:42:03
【问题描述】:

我有几个 cron 调用的 php 脚本。 cron 作业每 20 分钟运行一次。有时脚本在几分钟内完成工作,有时需要 20 多分钟。

我想在这里防止竞争条件。我想到的一种方法是使用数据库在页面运行时设置标志,并在作业完成时删除标志。但是我真的不想使用数据库。

还有其他解决办法吗?

【问题讨论】:

  • 每 30 分钟运行一次 cron 作业? ;-)
  • 感谢您的建议。它必须每 20 分钟运行一次;)

标签: php mysql cron


【解决方案1】:

(我使用过的)最好的方法是将进程 ID 保存在“锁定文件”中。

function getLock() {
    //First, check to see if the script is already running
    $data = @file_get_contents('path/to/process.pid');
    if ($data && posix_kill($data, 0)) {
        throw new RuntimeException(
            'Unable To Attain Lock, Another Process Is Still Running'
        );
    }
    file_put_contents('path/to/process.pid', posix_getpid());
}

基本上,它读取文件,然后尝试posix_kill 包含在里面的pid。请注意,当您使用0posix_kill 的信号时,它只会告诉您调用是否成功(意味着进程正在运行)。

这样做的好处是,如果进程在没有清理锁定文件的情况下死亡,它将被检测到并再次运行。

【讨论】:

  • 所以当工作完成后,我只需要取消链接 pid 文件,对吗?如果我杀死php进程会发生什么?
  • 您可以取消链接。这种方法的美妙之处在于您不必这样做。该文件所做的只是存储pid。因此,即使您不取消链接,它仍然可以正常工作(只要另一个进程没有在同一个 pid 上启动,这不太可能)...如果文件仍然存在,它会检查查看存储了pid 的进程是否仍在运行。如果不是(因为它死了,你杀死了它,或者它完成了),它将获得锁并继续执行......
  • 我在网页上试过这个,它工作得很好,但是当我从 shell 使用这个代码时它不起作用。可能是什么原因?
  • 嗯...也许是文件路径?我已经多次使用它(从外壳),它从来没有让我失望过。我会在另一个先运行时手动检查锁定文件是否存在,然后从那里开始......
  • 没有路径是好的。你有没有从 shell 和 web 一起尝试过这个?从 shell 中尝试第一个实例,从网页中尝试第二个实例,从另一个 shell 中尝试第三个实例。您会注意到第一个和最后一个可以正常工作(从 shell 或 web 运行)但第二个会卡住(与第一个和最后一个相反)
【解决方案2】:

您可以使用标记文件、共享内存区域或任何其他正常形式的进程间通信。镀金解决方案是实现一个小批量队列过程。

【讨论】:

  • 你能举个例子吗?
  • 作业运行时创建文件,作业完成后删除。如果作业再次运行,而另一个作业正在运行,请在开始之前检查此文件。
  • 批处理队列过程?对不起,我不能。我真的是一个 VMS 人,VMS 包括批处理。你想要的是一个小程序,它读取一个包含作业列表的文件,当它找到一个时,执行它,然后从文件中删除它。这涉及到一些进程同步。 Cron 作业不会执行该作业;他们将请求附加到文件中。以前一定有人这样做过;也许网络上的小拖网可能会出现一些东西。
  • 看看这个;这可能是您正在寻找的东西。 cs.ait.ac.th/~on/O/oreilly/unix/upt/ch40_06.htm
【解决方案3】:

您可以使用flock() 锁定预定义的“标志”文件,并在启动脚本之前检查该文件是否仍处于锁定状态。

【讨论】:

  • 我不推荐这个,如果脚本死了怎么办?
  • 是的,因此我没有使用文件锁定
  • 是的 - 您可以使用某种超时,但它可能不适用于这种频繁的任务。
  • @Stephen 如果脚本终止,所有的锁都会自动释放...这是 PHP 的一个特性(它会在脚本终止时清理资源)...
  • @ircmaxell 你测试过这个吗?因为当我为我以前的雇主这样做时,文件没有解锁。是的 php 有自动垃圾收集,但这并不意味着如果脚本死了它会解锁文件。测试一下,让脚本崩溃,看看文件是否被解锁。我敢打赌它仍然被锁定;)
【解决方案4】:

如果您创建一个 pid 文件来指示进程正在运行,请务必检查文件的创建时间,并设置一个阈值来判断多长时间。这样,如果您的工作在有机会删除它的 pid 文件之前就死了,那么您的工作就不会突然停止。

【讨论】:

    【解决方案5】:

    当然,临时文件 =]

    或者 fork 进程。在这里查看更多关于分叉的信息:http://php.net/manual/en/function.pcntl-fork.php

    建议:http://www.saynotoflash.com/archives/multi-process-php-execution/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-27
      • 1970-01-01
      相关资源
      最近更新 更多