【问题标题】:APC caching and atomic operationsAPC 缓存和原子操作
【发布时间】:2010-03-12 16:23:04
【问题描述】:

我正在考虑在我的应用程序中集成一些缓存逻辑。

主要是将对象和对象列表缓存到APC。我会 实现一种方法让它们自动失效,一旦对象 已更新/删除。

但是,原子性呢?如何确保操作是原子的?

【问题讨论】:

    标签: php apc


    【解决方案1】:

    好吧,如果您谈论的是单个操作,它将是原子的(基于 APC 的工作方式)。要么全部写出来,要么都不写……

    如果您正在谈论多个操作(如更新引用对象的每个位置),那么没有内置任何东西可以防止竞争条件。相反,您需要做的是实施某种锁定以防止其他进程尝试更新该数据。

    您可以这样做的一种方法是在开始操作之前通过将特殊锁定“缓存”项写入已知 id 来“锁定”每个缓存项(想想数据库中的行级锁定)。

    所以,假设一个受影响的缓存 id 数组:

    function getLocks($cacheIds) {
        $locked = array();
        foreach ($cacheIds as $cacheId) {
            if (apc_exists($cacheId . '_locked')) {
                //Another process has this id locked, clear all locks and return
                foreach ($locked as $id) apc_delete($id . '_locked');
                return false;
            } else {
                //Use a short TTL to prevent issues if this process dies
                apc_store($cacheId . '_locked', 60);
                $locked[] = $cacheId;
            }
        }
        return true;
    }
    
    function releaseLocks($cacheIds) {
        foreach ($cacheIds as $cacheId) {
            apc_delete($cacheId . '_locked');
        }
    }
    

    那么,你可以简单地调用:

    if (getLocks($cacheIds)) {
        //Do your operation here
        releaseLocks($cacheIds);
    }
    

    现在,请注意,这并不能防止两个进程同时检查同一个键的可能性很小(因此对于 apc_exists,两者都返回 false,但会相互覆盖)。如果这是一个大问题,那么您应该阅读double-checked locking

    【讨论】:

    • 这可能看起来在小范围内工作,但它不是线程安全的,并且在原子性很重要的情况下不是依赖的解决方案。双重检查锁定也不是解决方案。部分原因是您链接的文章中引用的许多原因,部分原因是 APC 的性质 (stackoverflow.com/questions/4468805/…)。如果 PHP 进程在放弃锁之前失败,也容易出现死锁。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-10
    相关资源
    最近更新 更多