У меня есть эта функция, которая пытается прочитать некоторые значения из кеша. Но если значение не существует, оно должно вызывать альтернативный API-интерфейс источника и сохранять новое значение в кеше. Однако сервер очень перегружен и почти каждый раз, когда значение не существует больше, чем один запрос создается (много вызовов API), и каждый из них будет хранить новую vale в кеше. Тем не менее, я хочу, чтобы иметь возможность вызывать 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?
fetch_cache
. Поместите sem_get()
в метод инициализации (например, __construct
). sem_remove()
, но в методе очистки (например, __destruct
). Или, возможно, вы захотите сохранить их еще дольше – зависит от логики вашего приложения. sem_acquire()
для получения блокировок и sem_release()
чтобы освободить их. sem_get()
Создает набор из трех семафоров.
semget
функция semget
не является атомарной . Существует вероятность состояния гонки, когда два процесса пытаются вызвать semget
. Поэтому semget
следует вызывать в процессе инициализации. Расширение PHP преодолевает эту проблему с помощью трех семафоров:
Семафор 0 aka SYSVSEM_SEM
Инициализируется на $max_acquire
и уменьшается, когда процессы его приобретают.
Первый процесс, который называется sem_get
получает значение семафора SYSVSEM_USAGE
(см. Ниже). Для первого процесса он равен 1
, потому что расширение устанавливает его в 1
с помощью атомной функции semop
сразу после semget
. И если это действительно первый процесс, расширение присваивает SYSVSEM_SEM
семафора $max_acquire
.
Семафор 1 aka SYSVSEM_USAGE
Количество процессов, использующих семафор.
Семафор 2 aka SYSVSEM_SETVAL
Воспроизводит роль блокировки для внутренних SETVAL
и GETVAL
(см. man 2 semctl
). Например, он установлен в 1
а расширение устанавливает SYSVSEM_SEM
в $max_acquire
, а затем возвращается к нулю.
Наконец, sem_get
обертывает структуру (содержащую идентификатор набора семафора, ключ и другую информацию) в ресурс PHP и возвращает его.
Поэтому вы должны назвать это в процессе инициализации, когда вы только готовитесь работать с семафорами.
sem_acquire()
Здесь $max_acquire
переходит в игру .
SYSVSEM_SEM
(назовем его semval
) первоначально равно $max_acquire
. semop()
до semval
пор, пока semval
станет больше или равно 1
. Тогда 1
semval
из semval
.
Если $max_acquire = 1
, то semval
становится нулевым после первого вызова, а следующий вызывает блок заполнения sem_acquire()
пока semval
будет восстановлен sem_release()
.
Назовите его, когда вам нужно приобрести следующий «замок» из доступного набора ( $max_acquire
).
sem_release()
В значительной степени sem_acquire()
, за исключением того, что он увеличивает значение SYSVSEM_SEM
.
Назовите это, когда вам больше не понадобится «блокировка», приобретенная ранее с помощью sem_acquire()
.
sem_remove()
Немедленно удаляет набор семафоров, пробуждая все процессы, заблокированные в semop
на наборе (из раздела IPC_RMID , справочная страница SEMCTL (2) ).
Таким образом, это фактически то же самое, что удаление семафора с ipcrm
команды ipcrm
.