Как избежать гоночной опасности с несколькими запросами?

В целях защиты от гонки по сценарию я рассматриваю подход, описанный в примере кода.

$file = 'yxz.lockctrl';
// if file exists, it means that some other request is running
while (file_exists($file))
{
sleep(1);
}

file_put_contents($file, '');

// do some work

unlink($file);

Если я пойду по этому пути, возможно ли создать файл с одинаковым именем одновременно из нескольких запросов?

Я знаю, что есть php mutex. Я хотел бы справиться с этой ситуацией без каких-либо расширений (если это возможно).

Задача программы — обрабатывать заявки в аукционах. Я хотел бы обрабатывать каждый запрос ставки последовательно. С максимально возможной задержкой.

0

Решение

Из того, что я понимаю, вы хотите убедиться, что только один процесс одновременно выполняет определенный фрагмент кода. Для этого может использоваться мьютекс или аналогичный механизм. Я сам использую файлы блокировки, чтобы иметь решение, которое работает на многих платформах и не полагается на конкретную библиотеку, доступную только в Linux и т. Д.

Для этого я написал небольшой Lock учебный класс. Обратите внимание, что он использует некоторые нестандартные функции из моей библиотеки, например, чтобы найти место для хранения временных файлов и т. Д. Но вы можете легко это изменить.

<?php
class Lock
{
private $_owned             = false;

private $_name              = null;
private $_lockFile          = null;
private $_lockFilePointer   = null;

public function __construct($name)
{
$this->_name = $name;
$this->_lockFile = PluginManager::getInstance()->getCorePlugin()->getTempDir('locks') . $name . '-' . sha1($name . PluginManager::getInstance()->getCorePlugin()->getPreference('EncryptionKey')->getValue()).'.lock';
}

public function __destruct()
{
$this->release();
}

/**
* Acquires a lock
*
* Returns true on success and false on failure.
* Could be told to wait (block) and if so for a max amount of seconds or return false right away.
*
* @param bool $wait
* @param null $maxWaitTime
* @return bool
* @throws \Exception
*/
public function acquire($wait = false, $maxWaitTime = null) {
$this->_lockFilePointer = fopen($this->_lockFile, 'c');
if(!$this->_lockFilePointer) {
throw new \RuntimeException(__('Unable to create lock file', 'dliCore'));
}

if($wait && $maxWaitTime === null) {
$flags = LOCK_EX;
}
else {
$flags = LOCK_EX | LOCK_NB;
}

$startTime = time();

while(1) {
if (flock($this->_lockFilePointer, $flags)) {
$this->_owned = true;
return true;
} else {
if($maxWaitTime === null || time() - $startTime > $maxWaitTime) {
fclose($this->_lockFilePointer);
return false;
}
sleep(1);
}
}
}

/**
* Releases the lock
*/
public function release()
{
if($this->_owned) {
@flock($this->_lockFilePointer, LOCK_UN);
@fclose($this->_lockFilePointer);
@unlink($this->_lockFile);
$this->_owned = false;
}
}
}

использование

Теперь у вас может быть два процесса, которые запускаются одновременно и выполняют один и тот же скрипт.

Процесс 1

$lock = new Lock('runExpensiveFunction');

if($lock->acquire()) {
// Some expensive function that should only run one at a time
runExpensiveFunction();
$lock->release();
}

Процесс 2

$lock = new Lock('runExpensiveFunction');

// Check will be false since the lock will already be held by someone else so the function is skipped
if($lock->acquire()) {
// Some expensive function that should only run one at a time
runExpensiveFunction();
$lock->release();
}

Другой альтернативой было бы заставить второй процесс ждать завершения первого, а не пропускать код.

$lock = new Lock('runExpensiveFunction');

// Process will now wait for the lock to become available. A max wait time can be set if needed.
if($lock->acquire(true)) {
// Some expensive function that should only run one at a time
runExpensiveFunction();
$lock->release();
}

Рам диск
Чтобы ограничить количество операций записи на жесткий диск / твердотельный накопитель с помощью файлов блокировки, вы можете создать диск RAM для их хранения.

В линуксе Вы можете добавить что-то вроде следующего /etc/fstab

tmpfs       /mnt/ramdisk tmpfs   nodev,nosuid,noexec,nodiratime,size=1024M   0 0

На винде Вы можете скачать что-то вроде ImDisk Toolkit и создать виртуальный диск с этим.

ImDisk RamDisk Конфигурационный инструмент

0

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

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

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