Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > Одновременное выполнение операции


Автор: quiz 8.10.2007, 21:32
Здравствуйте.
Помогите, пожалуйста, справиться с проблемой, голову уже сломал smile 

Суть проблемы - на сервере есть скрипт, который в процессе выполнения достает значение "calc_done" из mysql-таблицы и если это значение == 0, то начинает выполнять довольно массивные циклы математических операций, SELECT-UPDATE таблиц и т.п. 

Когда скрипт запускается одним человеком - все окей. Но когда его одновременно выполняют десятки людей, то те самые массивные операции начинают время от времени дублироваться. Видимо скрипт запускается 1 раз и пока апдейт значения calc_done=1 не произведен, кто-либо успевает запустить этот же скрипт еще раз.

Апдейт значения делаю сразу же после условия, но это не помогает

Код

$exm= mysql_query("SELECT * FROM test WHERE myid=1");
$exm = mysql_fetch_array($exm);    
if ($exm[calc_done]==0) {
   mysql_query("UPDATE test SET calc_done=1 WHERE myid=1");

   .....................................
   массивная куча кода...
   .....................................

}



Мануал MySQL по блокировке таблиц читал - частично понял, частично нет. Пробовал расставить блокировки - не помогло. Может не так делал, а может в моем случае нужны вовсе не блокировки таблиц?

Автор: chin 8.10.2007, 22:02
Добавьте еще одно поле типа calc_process, перед началом просчета ставьте туда 1, после окончания, сбрасывайте на 0. Измените выражение на
Код

if ($exm['calc_done'] == 0 && $exm['calc_process'] == 0) {

Заключайте в кавычки ключи массивов.

Хотя, если у Вас сразу идет обновление calc_done = 1, то никакой скрипт не успеет прошустрить в этот короткий интервал. Разве что, если у Вас тормозит БД и запрос на update проходит очень долго.
Таблица test не обновляется в Вашей "массивной куче кода"?

Автор: quiz 8.10.2007, 22:06
то есть так?

Код

$exm= mysql_query("SELECT * FROM test WHERE myid=1");
$exm = mysql_fetch_array($exm);    

mysql_query("UPDATE test SET calc_process=1 WHERE myid=1");

if ($exm['calc_done'] == 0 && $exm['calc_process'] == 0) {
   mysql_query("UPDATE test SET calc_done=1 WHERE myid=1");

   .....................................
   массивная куча кода...
   .....................................

}
mysql_query("UPDATE test SET calc_process=0 WHERE myid=1");


А в чем смысл? Ведь calc_done=1 присваивается почти там же, на 2 строки выше

И чем плохи ключи массивов без кавычек?

Добавлено через 3 минуты и 32 секунды
Цитата(chin @ 8.10.2007,  22:02)
Хотя, если у Вас сразу идет обновление calc_done = 1, то никакой скрипт не успеет прошустрить в этот короткий интервал. Разве что, если у Вас тормозит БД и запрос на update проходит очень долго.
Таблица test не обновляется в Вашей "массивной куче кода"?

Нет, таблица обновляется только calc_done=1

Автор: chin 8.10.2007, 22:13
Ладно, давайте померяем:
Код

$time = array();

$time['select'] = array_sum(explode(" ", microtime()));
$exm= mysql_query("SELECT * FROM test WHERE myid=1");
$exm = mysql_fetch_array($exm);
$time['select'] = array_sum(explode(" ", microtime())) - $time['select'];

$time['update'] = array_sum(explode(" ", microtime()));
if ($exm['calc_done'] == 0 && $exm['calc_process'] == 0) {
   mysql_query("UPDATE test SET calc_done=1 WHERE myid=1");
   $time['update'] = array_sum(explode(" ", microtime())) - $time['update'];
   print_r($time);
   exit;

Автор: quiz 8.10.2007, 22:32
select 0.00094389915466309
update 0.0024709701538086

Автор: chin 8.10.2007, 23:01
Мда, ну за такое время мало что может случиться...
Уберите calc_process, он уже не поможет ;)
Кажется, тайна кроется в "массивной куче кода"...

Автор: quiz 8.10.2007, 23:03
действительно, в такое время 2 клиента вряд ли уложиться сумеют. Ищу ошибку в коде

Автор: quiz 9.10.2007, 22:33
нашел ошибку, спасибо

Автор: chin 9.10.2007, 23:13
и в чем же была ошибка?

Автор: theworldcreator 10.10.2007, 11:50
А почему не может быть так, что два скрипта одновременно запросили calc_done равный нулю(mysql их по очереди выполнит) и стали дальше выполняться - оба поочереди поставят calc_done=1 ну и станут выполнять массивную кучу кода? Маловероятно, но возможно.

Автор: solenko 10.10.2007, 13:41
quiz:
Цитата

И чем плохи ключи массивов без кавычек?

Если я правильно понимаю, то при обращении без кавычек вы пытаетесь обратиться к константе, которой не существует, а значит php ее создает и присваивает ей строку с ее именем.
попробуйте error_reporting(E_ALL);

Автор: quiz 10.11.2007, 17:11
Цитата(theworldcreator @ 10.10.2007,  11:50)
А почему не может быть так, что два скрипта одновременно запросили calc_done равный нулю(mysql их по очереди выполнит) и стали дальше выполняться - оба поочереди поставят calc_done=1 ну и станут выполнять массивную кучу кода? Маловероятно, но возможно.

Так оно и оказалось :(

Когда посетителей, выполняющих скрипт немного - то все ок.
Когда посетителей становится много, скорость запросов к базе резко падает и постоянно в этот промежуток (calc_done=0) попадают 2-3-4 пользователя. Соответственно код выполняется более, чем 1 раз :(

Поэтому проблема все еще актуальна - помогите найти выход, пожалуйста

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)