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

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

3

Решение

  1. Вам не нужно создавать и удалять семафоры в пределах fetch_cache функция. Положил sem_get() в метод инициализации (например, __construct).
  2. Вы должны удалить семафоры с sem_remove(), но в методе очистки (например, __destruct). Или, возможно, вы захотите сохранить их еще дольше — зависит от логики вашего приложения.
  3. использование sem_acquire() приобрести замки и sem_release() выпустить их.

sem_get()

Создает набор три семафоры.

Основная функция C semget является не атомный. Существует возможность состояние гонки когда два процесса пытаются вызвать semget, Следовательно, semget должен быть вызван в некотором процессе инициализации. Расширение PHP решает эту проблему с помощью трех семафоров:

Семафор 0 а.к.а. SYSVSEM_SEM

Инициализируется в sem_get«s $max_acquire и уменьшается по мере того, как процессы приобретают его.

Первый процесс, который называется sem_get извлекает значение SYSVSEM_USAGEсемафор (см. ниже). Для первого процесса это равняется 1потому что расширение устанавливает его 1 с атомным semop функционировать сразу после semget, И если это действительно первый процесс, расширение назначает SYSVSEM_SEM значение семафора в $max_acquire,

Семафор 1 а.к.а. SYSVSEM_USAGE

Количество процессов, использующих семафор.

Семафор 2 а.к.а. SYSVSEM_SETVAL

Играет роль замка для внутреннего SETVAL а также GETVAL операции (см. man 2 semctl). Например, он установлен на 1 в то время как расширение устанавливает SYSVSEM_SEM в $max_acquire, затем обнуляется.

В заключение, sem_get оборачивает структуру (содержащую ID набора семафоров, ключ и другую информацию) в ресурс PHP и возвращает его.

Поэтому вы должны вызывать его в некотором процессе инициализации, когда вы только готовитесь к работе с семафорами.

sem_acquire()

Это где $max_acquire входит в игру.

SYSVSEM_SEMценность (давайте назовем это semval) изначально равен $max_acquire, semop() блоки до semval становится больше или равно 1, затем 1 вычитается из 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 команда.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]