У меня есть эта функция, которая пытается прочитать некоторые значения из кеша. Но если значение не существует, оно должно вызывать альтернативный 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 .