我有这个函数试图从缓存中读取一些值。但是如果值不存在,它应该调用替代源 API 并将新值保存到缓存中。但是,服务器非常过载,几乎每次当值不存在时都会创建一个请求(大量 API 调用),并且每个请求都会将新值存储到缓存中。但是,我想要的是能够多次调用 API,但只有一个进程/请求能够将其存储在缓存中:
function fetch_cache($key, $alternativeSource) {
$redis = new Redis();
$redis->pconnect(ENV_REDIS_HOST);
$value = $redis->get($key);
if( $value === NULL ) {
$value = file_get_contents($alternativeSource);
// here goes part that I need help with
$semaphore = sem_get(6000, 1); // does this need to be called each time this function is called?
if( $semaphore === FALSE ) {
// This means I have failed to create semaphore?
}
if( sem_aquire($semaphore, true) ) {
// we have aquired semaphore so here
$redis->set($key, $value);
sem_release($semaphore); // releasing lock
}
// This must be call because I have called sem_get()?
sem_remove($semaphore);
}
return $value;
}
Run Code Online (Sandbox Code Playgroud)
这是在 PHP5 中正确使用信号量吗?
fetch_cache函数内创建和删除信号量。放入sem_get()初始化方法(如__construct)。sem_remove(), 但在清理方法(例如__destruct)中删除信号量。或者,您可能希望将它们保留更长时间 - 取决于您的应用程序的逻辑。sem_acquire()获取锁,并sem_release()释放他们。sem_get()创建一组三个信号量。
底层的C函数semget是不是原子。还有的可能性竞争条件,当两个进程试图调用semget。因此,semget应该在一些初始化过程中调用。PHP 扩展通过三个信号量克服了这个问题:
信号量 0 又名 SYSVSEM_SEM
初始化为sem_get's$max_acquire并随着进程获取它而递减。
调用的第一个进程sem_get获取SYSVSEM_USAGE信号量的值(见下文)。对于第一个进程,它等于1,因为扩展将它设置为1紧跟semop在 之后的原子函数semget。如果这确实是第一个进程,则扩展将SYSVSEM_SEM信号量值分配给$max_acquire。
信号量 1 又名 SYSVSEM_USAGE
使用信号量的进程数。
信号量 2 又名 SYSVSEM_SETVAL
对内部SETVAL和GETVAL操作起到锁的作用(请参阅 参考资料man 2 semctl)。例如,它被设定为1当该扩展程序集SYSVSEM_SEM到$max_acquire,然后被重置回零。
最后,sem_get将一个结构体(包含信号量集合ID、key等信息)包装成一个PHP资源并返回。
所以你应该在一些初始化过程中调用它,当你只准备使用信号量时。
sem_acquire()这是$max_acquire 发挥作用的地方。
SYSVSEM_SEM的值(我们称之为semval)最初等于$max_acquire。semop()阻塞直到semval变得大于或等于1。然后1从 中减去semval。
如果$max_acquire = 1,则semval在第一次调用后变为零,下一次调用sem_acquire()将阻塞,直到semval被sem_release()调用恢复。
当您需要从可用集合 ( $max_acquire) 中获取下一个“锁”时调用它。
sem_release()与 几乎相同sem_acquire(),只是它增加了SYSVSEM_SEM的值。
当您不再需要之前使用sem_acquire().
sem_remove()立即删除信号集,唤醒allprocesses阻塞在semop该组(从IPC_RMID节了semctl(2)手册页)。
所以这实际上与使用ipcrm命令删除信号量相同。
| 归档时间: |
|
| 查看次数: |
5446 次 |
| 最近记录: |