Как правильно использовать семафоры PHP5?

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

Solutions Collecting From Web of "Как правильно использовать семафоры PHP5?"

Короткий ответ

  1. Вам не нужно создавать и удалять семафоры в функции fetch_cache . Поместите sem_get() в метод инициализации (например, __construct ).
  2. Вы должны удалить семафоры с помощью sem_remove() , но в методе очистки (например, __destruct ). Или, возможно, вы захотите сохранить их еще дольше – зависит от логики вашего приложения.
  3. Используйте 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 .