如何正确使用PHP5信号灯? [英] How to properly use PHP5 semaphores?

查看:101
本文介绍了如何正确使用PHP5信号灯?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个功能,试图从缓存中读取一些值.但是,如果值不存在,则应调用备用源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?

推荐答案

简短答案

  1. 您不需要在fetch_cache函数中创建和删除信号量.将sem_get()放入初始化方法(例如__construct).
  2. 您应使用sem_remove()删除信号量,但应使用清理方法(例如__destruct).或者,您可能希望将它们保留更长的时间-取决于应用程序的逻辑.
  3. 使用sem_acquire()获取锁,然后使用sem_release()释放锁.
  1. You don't need to create and remove semaphores within the fetch_cache function. Put sem_get() into an initialization method (such as __construct).
  2. 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.
  3. Use sem_acquire() to acquire locks, and sem_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_USAGEsemaphore (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

充当内部SETVALGETVAL操作的锁(请参见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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆