У меня есть эта функция, которая пытается прочитать некоторые значения из кэша. Но если значение не существует, он должен вызвать 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?
fetch_cache
функция. Положил sem_get()
в метод инициализации (например, __construct
).sem_remove()
, но в методе очистки (например, __destruct
). Или, возможно, вы захотите сохранить их еще дольше — зависит от логики вашего приложения.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
команда.
Других решений пока нет …