如何正确使用PHP5信号灯? [英] How to properly use PHP5 semaphores?
问题描述
我有这个功能,试图从缓存中读取一些值.但是,如果值不存在,则应调用备用源API并将新值保存到缓存中.但是,服务器非常过载,几乎每次不存在值时,就会创建一个请求(许多API调用),并且每个请求都会将新值存储到缓存中.但是,我想要的是能够多次调用API,但是只有一个进程/请求能够将其存储在缓存中:
I have this function that tries to read some values from cache. But if value does not exists it should call alternative source API and save new value into the cache. However, server is very overloaded and almost each time when value does not exists more then one requests are created (a lot of API calls) and each of them will store new vale into cache. However, what I want is to be able to call API many times, but only one process/request to be able to store it in cache:
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;
}
在PHP5中是否正确使用了信号量?
Is this proper use of semaphore in PHP5?
推荐答案
简短答案
- 您不需要在
fetch_cache
函数中创建和删除信号量.将sem_get()
放入初始化方法(例如__construct
). - 您应使用
sem_remove()
删除信号量,但应使用清理方法(例如__destruct
).或者,您可能希望将它们保留更长的时间-取决于应用程序的逻辑. - 使用
sem_acquire()
获取锁,然后使用sem_release()
释放锁.
- You don't need to create and remove semaphores within the
fetch_cache
function. Putsem_get()
into an initialization method (such as__construct
). - You should remove semaphores with
sem_remove()
, but in a cleanup method (such as__destruct
). Or, you might want to keep them even longer - depends on the logic of your application. - Use
sem_acquire()
to acquire locks, andsem_release()
to release them.
说明
sem_get()
创建一组三信号量.
Description
sem_get()
Creates a set of three semaphores.
底层C函数semget
不是原子的.当两个进程尝试调用semget
时,可能会竞赛条件.因此,应在某些初始化过程中调用semget
. PHP扩展通过三个信号量克服了这个问题:
The underlying C function semget
is not atomic. There is a possibility of race condition when two processes trying to call semget
. Therefore, semget
should be called in some initialization process. The PHP extension overcomes this issue by means of three semaphores:
信号量0又称SYSVSEM_SEM
被初始化为sem_get
的$max_acquire
,并随着进程的获取而递减.
Is initialized to sem_get
's $max_acquire
and decremented as processes acquires it.
第一个调用sem_get
的进程将获取SYSVSEM_USAGE
信号量的值(请参见下文).对于第一个过程,它等于1
,因为扩展名紧随semget
之后,使用原子semop
函数将其设置为1
.而且,如果这确实是第一个过程,则扩展会将SYSVSEM_SEM
信号量值分配给$max_acquire
.
The first process that called sem_get
fetches the value of SYSVSEM_USAGE
semaphore (see below). For the first process, it equals to 1
, because the extension sets it to 1
with atomic semop
function right after semget
. And if this is really the first process, the extension assigns SYSVSEM_SEM
semaphore value to $max_acquire
.
信号量1又称SYSVSEM_USAGE
使用信号量的进程数.
信号量2又称SYSVSEM_SETVAL
充当内部SETVAL
和GETVAL
操作的锁(请参见man 2 semctl
).例如,将其设置为1
,而将扩展名将SYSVSEM_SEM
设置为$max_acquire
,然后将其重置为零.
Plays a role of a lock for internal SETVAL
and GETVAL
operations (see man 2 semctl
). For example, it is set to 1
while the extension sets SYSVSEM_SEM
to $max_acquire
, then is reset back to zero.
最后,sem_get
将一个结构(包含信号量集ID,键和其他信息)包装到PHP资源中并返回它.
Finally, sem_get
wraps a structure (containing the semaphore set ID, key and other information) into a PHP resource and returns it.
因此,当您仅准备使用信号量时,应该在一些初始化过程中调用它.
So you should call it in some initialization process, when you're only preparing to work with semaphores.
这是$max_acquire
转到的地方发挥作用.
SYSVSEM_SEM
的值(我们称其为semval
)最初等于$max_acquire
. semop()
阻塞,直到semval
大于或等于1
.然后从semval
中减去1
.
SYSVSEM_SEM
's value (let's call it semval
) is initially equal to $max_acquire
. semop()
blocks until semval
becomes greater than or equal to 1
. Then 1
is substracted from semval
.
如果为$max_acquire = 1
,则在第一次调用后semval
变为零,并且对sem_acquire()
填充块的下一次调用直到semval
通过sem_release()
调用恢复.
If $max_acquire = 1
, then semval
becomes zero after the first call, and the next calls to sem_acquire()
fill block until semval
is restored by sem_release()
call.
需要从可用组($max_acquire
)中获取下一个锁"时调用它.
Call it when you need to acquire the next "lock" from the available set ($max_acquire
).
与sem_acquire()
几乎相同,不同之处在于它会增加SYSVSEM_SEM
的值.
Does pretty much the same as sem_acquire()
, except it increments SYSVSEM_SEM
's value.
在您不再需要使用sem_acquire()
先前获得的锁"时调用它.
Call it when you need to no longer need the "lock" acquired previously with sem_acquire()
.
立即删除信号量集,唤醒集合中semop
中阻塞的所有进程(来自IPC_RMID
部分, SEMCTL(2)手册页).
Immediately removes the semaphore set, awakening allprocesses blocked in semop
on the set (from IPC_RMID
section, SEMCTL(2) man page).
因此,这实际上与使用ipcrm
命令删除信号量相同.
So this is effectively the same as removing a semaphore with ipcrm
command.
这篇关于如何正确使用PHP5信号灯?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!