【发布时间】:2010-03-12 16:23:04
【问题描述】:
我正在考虑在我的应用程序中集成一些缓存逻辑。
主要是将对象和对象列表缓存到APC。我会 实现一种方法让它们自动失效,一旦对象 已更新/删除。
但是,原子性呢?如何确保操作是原子的?
【问题讨论】:
我正在考虑在我的应用程序中集成一些缓存逻辑。
主要是将对象和对象列表缓存到APC。我会 实现一种方法让它们自动失效,一旦对象 已更新/删除。
但是,原子性呢?如何确保操作是原子的?
【问题讨论】:
好吧,如果您谈论的是单个操作,它将是原子的(基于 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
【讨论】: