gpt4 book ai didi

php - 如何正确使用PHP5信号量?

转载 作者:可可西里 更新时间:2023-10-31 23:16:44 27 4
gpt4 key购买 nike

我有这个函数试图从缓存中读取一些值。但如果值不存在,它应该调用替代源 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;
}

在 PHP5 中这样使用信号量是否正确?

最佳答案

简答

  1. 您不需要在 fetch_cache 函数中创建和删除信号量。将sem_get()放入一个初始化方法中(如__construct)。
  2. 您应该使用 sem_remove() 删除信号量,但要使用清理方法(例如 __destruct)。或者,您可能希望将它们保留更长时间 - 取决于您的应用程序的逻辑。
  3. 使用 sem_acquire() 获取锁,使用 sem_release() 释放锁。

描述

sem_get()

创建一组 three信号量。

底层 C 函数 semget非原子的。有可能是race condition当两个进程试图调用 semget 时。因此,在一些初始化过程中应该调用semget。 PHP 扩展通过三个信号量解决了这个问题:

信号量 0 又名 SYSVSEM_SEM

初始化为 sem_get$max_acquire 并随着进程获取它而递减。

调用 sem_get 的第一个进程获取 SYSVSEM_USAGE 信号量的值(见下文)。对于第一个进程,它等于 1,因为扩展名 sets it to 1semget 之后使用原子 semop 函数。如果这确实是第一个进程,则扩展会将 SYSVSEM_SEM 信号量值分配给 $max_acquire

信号量 1 又名 SYSVSEM_USAGE

使用信号量的进程数。

信号量 2 又名 SYSVSEM_SETVAL

对内部 SETVALGETVAL 操作起到锁的作用(参见 man 2 semctl)。例如,它设置为 1,而扩展将 SYSVSEM_SEM 设置为 $max_acquire,然后重置为零。

最后,sem_get将一个结构体(包含信号量集ID、key等信息)封装到PHP资源中并返回。

所以当您只准备使用信号量时,您应该在一些初始化过程中调用它。

sem_acquire()

这是 $max_acquire goes into play 的位置.

SYSVSEM_SEM 的值(我们称之为 semval)最初等于 $max_acquiresemop() 阻塞,直到 semval 变得大于或等于 1。然后从semval中减去1

如果 $max_acquire = 1,则 semval 在第一次调用后变为零,下一次调用 sem_acquire() 将阻塞,直到semvalsem_release() 调用恢复。

当您需要从可用集合 ($max_acquire) 中获取下一个“锁”时调用它。

sem_release()

sem_acquire() 几乎相同,只是它增加了 SYSVSEM_SEM 的值。

当您不再需要之前使用 sem_acquire() 获取的“锁”时调用它。

sem_remove()

立即删除信号量集,唤醒在该集的 semop 中阻塞的所有进程(来自 IPC_RMID 部分,SEMCTL(2) 手册页) .

所以这实际上与使用 ipcrm 命令删除信号量相同。

关于php - 如何正确使用PHP5信号量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39976805/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com