【发布时间】:2010-10-21 17:12:09
【问题描述】:
我有一个实时执行更新功能的脚本。我会将其移至 cron 作业,但由于某些限制,我更愿意让它在页面加载时运行并调用。
问题是,当流量很大时,它就不太好用了,因为它使用了一些随机的加权数字,所以如果它被点击了很多次,结果就不是我们想要的。
所以,问题是。有没有办法知道特定脚本被访问了多少次?并且一次只能限制一次?
谢谢!
【问题讨论】:
标签: php
我有一个实时执行更新功能的脚本。我会将其移至 cron 作业,但由于某些限制,我更愿意让它在页面加载时运行并调用。
问题是,当流量很大时,它就不太好用了,因为它使用了一些随机的加权数字,所以如果它被点击了很多次,结果就不是我们想要的。
所以,问题是。有没有办法知道特定脚本被访问了多少次?并且一次只能限制一次?
谢谢!
【问题讨论】:
标签: php
您正在寻找的技术称为锁定。
最简单的方法是创建一个临时文件,并在操作完成后将其删除。其他进程将查找该临时文件,发现它已经存在并消失。
但是,您还需要注意锁的所有者进程崩溃以及无法移除锁的可能性。这就是这个简单的任务似乎变得复杂的地方。
基于文件的锁定解决方案
PHP 有一个内置的flock() 函数,它承诺提供独立于操作系统的基于文件的锁定功能。 This question 有一些关于如何使用它的实用提示。但是,手册页警告说,在某些情况下,flock() 在尝试同时获得锁定的多个 PHP 脚本实例方面存在问题。 This question 在这个问题上似乎有更高级的答案,但它们都不是微不足道的。
基于数据库的锁定
this question 的作者 - 可能被 flock() 周围的复杂性吓跑了 - 寻求其他非基于文件的锁定技术,并提出了 MySQL 的 GET_LOCK()。我从未使用过它,但它看起来很简单——如果你仍然使用 mySQL,它可能值得一试。
该死,如果你想把它做好的话,这个问题很复杂!有兴趣看看是否有更优雅的东西出现。
【讨论】:
你可以这样做(需要 PHP 5):
if(file_get_contents("lock.txt") == "unlocked"){
// no lock present, so place one
file_put_contents("lock.txt", "locked");
// do your processing
...
// remove the lock
file_put_contents("lock.txt", "unlocked", LOCK_EX);
}
file_put_contents() 默认情况下会覆盖文件(而不是追加),因此文件的内容应该永远是“锁定”或什么都没有。您需要指定 LOCK_EX 标志,以确保在您尝试写入文件时,该文件当前未被脚本的另一个实例打开。
显然,正如@Pekka 在他的回答中提到的那样,如果在放置锁定和删除锁定之间发生致命错误(或 PHP 崩溃,或服务器崩溃等),这可能会导致问题,因为文件将简单保持锁定状态。
【讨论】:
使用 sql 查询启动脚本,该查询测试数据库中的时间戳字段是否超过 1 天前。 如果是 - 写入当前时间戳并执行脚本。
伪sql来展示思路:
UPDATE runs SET lastrun=NOW() WHERE lastrun<NOW()-1DAY
(不同的sql server会在上面做不同的改动)
检查更新了多少行以查看此脚本运行是否获得了锁定。 不要使用两个查询 - SELECT 和 UPDATE,因为它不再是原子的。
【讨论】:
UPDATE [runs] SET [lastrun] = GETDATE() WHERE [IDrun]= 1 AND [lastrun] < DATEADD(dd, -1, GETDATE())
UPDATE [runs] SET [lastrun] = DATEADD(dd, -1, GETDATE()) WHERE [IDrun]= 1 来释放“锁定”,以便脚本可以再次运行。