Остановить 2 одинаковых запроса от выполнения почти одновременно? - PullRequest
3 голосов
/ 14 марта 2010

Я разработал игру на основе AJAX, в которой есть ошибка (очень удаленная, но по объему это происходит не реже одного раза в час), когда по какой-то причине два запроса отправляются на страницу обработки почти одновременно (последний, который отслеженные запросы были разницей в 0,0001 мс). Перед выполнением запроса выполняется проверка, чтобы удостовериться, что он не будет выполнен дважды, но, поскольку разница настолько мала, проверка не завершилась до выполнения следующего запроса. Я в тупике, как я могу предотвратить это, поскольку это вызывает серьезные проблемы в игре.

Просто чтобы быть более понятным, запрос запускает новый раунд в игре, поэтому, когда он выполняется дважды, он начинает 2 раунда одновременно, что прерывает игру, поэтому мне нужно иметь возможность остановить сценарий от выполнение, если предыдущий раунд не закончился, даже если этот предыдущий раунд начался .0001 мс назад.

Ответы [ 3 ]

3 голосов
/ 14 марта 2010

Хитрость заключается в том, чтобы использовать атомарный оператор обновления, чтобы сделать что-то, что не может быть успешным для обоих потоков. Оба они не должны быть успешными, поэтому вы можете просто выполнить запрос вроде:

UPDATE gameinfo SET round=round+1 WHERE round=1234

Где 1234 - текущий раунд, который был в процессе. Затем проверьте количество затронутых строк. Если поток влияет на ноль строк, он потерпел неудачу, и кто-то другой сделал это заранее. Я предполагаю, что вышеупомянутое будет выполнено в его собственной транзакции, когда автокоммит включен.

1 голос
/ 14 марта 2010

Так что все, что вам действительно нужно, - это мьютекс всего приложения. flock () sem_acquire () обеспечивает это - но только на системном уровне - если приложение распределено по разным серверам, вам нужно использовать memcached или реализовать свой собственный сервер сокетов для координации узлов.

В качестве альтернативы вы можете использовать базу данных в качестве общей области хранения - например, с помощью MySQL установите блокировку таблицы, проверьте, когда раунд последний раз был запущен, при необходимости обновите строку, чтобы сообщить, что начинается новый раунд (и запомните это - затем разблокируйте таблицу. Продолжайте ....

С

0 голосов
/ 14 марта 2010

Блокировки - один из способов сделать это, но в некоторых случаях проще сделать ваш запрос идемпотентным. Это просто означает, что повторный вызов имеет точно такой же эффект, как и один раз.

Например, ваш звонок в данный момент эффективно выполняет $round++; Четко повторные звонки вызовут проблемы.

Но вы могли бы вместо этого сделать $round=$newround; Здесь повторные вызовы не будут иметь никакого эффекта, потому что раунд уже установлен, и второй вызов просто устанавливает его на то же значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...