我有一个实时更新功能的脚本。我会把它转移到一个cron工作,但由于一些限制,我宁愿让它活动并在页面加载时调用。
问题在于,当有大量流量时,它并不能正常工作,因为它使用了一些随机和加权数字,所以如果它经常发生一次,结果就不是我们想要的了。 / p>
所以,问题是。有没有办法告诉特定脚本被访问了多少次?并且一次只能限制一次?
谢谢!
答案 0 :(得分:5)
您正在寻找的技术称为锁定。
最简单的方法是创建一个临时文件,并在操作完成后将其删除。其他进程将查找该临时文件,看它已经存在并消失。
但是,您还需要注意锁定所有者进程崩溃的可能性,并且无法删除锁定。这就是这个简单的任务似乎变得复杂的地方。
基于文件的锁定解决方案
PHP有一个内置的flock()
函数,它承诺独立于操作系统的基于文件的锁定功能。 This question有一些关于如何使用它的实用提示。但是,手册页警告说,在某些情况下,flock()
在尝试同时获取锁定的多个PHP脚本实例时出现问题。 This question似乎在这个问题上有更高级的答案,但实施起来并不容易。
基于数据库的锁定
this question的作者 - 可能会被flock()
的复杂问题吓跑 - 请求其他的,而不是基于文件的锁定技术,并提出MySQL的GET_LOCK()
。我从来没有使用它,但它看起来很简单 - 如果你使用mySQL,它可能值得一试。
该死的,如果你想做的话,这个问题是复杂的!有兴趣看看是否有更优雅的东西出现。
答案 1 :(得分:3)
你可以这样做(需要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崩溃,或服务器崩溃等等),这可能会导致问题,因为文件将简单保持锁定。
答案 2 :(得分:1)
使用sql查询启动脚本,该查询测试数据库中的时间戳字段是否超过1天。 如果是 - 写下当前时间戳并执行脚本。
伪sql来表明这个想法:
UPDATE runs SET lastrun=NOW() WHERE lastrun<NOW()-1DAY
(不同的sql server将需要在上面进行不同的更改)
检查已更新的行数以查看此脚本是否获得锁定。 不要使用两个查询 - SELECT和UPDATE,因为它不再是原子。