Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Может скрипт php работать вечно?

714
08 августа 2012 года
clgs
226 / / 29.10.2008
Поступила задача: нужно написать скрипт который будет выполнять некие действия при этом скрипт может быть запущен только один экземпляр и работать должен 7/24.
Проблема в том что при нормальной работе скрипта, ростёт используемая память. В нете много подобных вопросов, но ответа не смог найти. Как это вообще можно побороть? Есть идея при работе смотреть сколько использует, при превышении определенного порога останавливать и запускать новый экземпляр, но это уход от поставленной задачи.


Вот небольшой пример:

Оба варианта работали 20 минут. Код не имеет не какого практического смысла.
Код:
public function run(){
        while(true){
            $this->_isStop();
            $res=Query('SELECT * FROM table');
            while($row=mysql_fetch_assoc($res)){
                foreach($row AS $k=>$r){
                    $r==$row[$k];
                }
            }
            unset($res,$row,$k,$r);
            sleep(5);
        }
    }
В начале запуска 5.57Mb, после 20 минут работы 5.57Mb

Код:
public function run(){
        $this->_isStop();
        $res=Query('SELECT * FROM table');
        while($row=mysql_fetch_assoc($res)){
            foreach($row AS $k=>$r){
                $r==$row[$k];
            }
        }
        unset($res,$row,$k,$r);
        sleep(5);
        $this->run();
    }
В начале запуска 5.52Mb, после 20 минут работы 5.64Mb.

Получается первый вариант не увеличил кол-во используемой памяти, но с точки зрения практики - написать рабочий код так, затруднительно.
1
08 августа 2012 года
kot_
7.3K / / 20.01.2000
я решил жить вечно - пока получается (с) :)
по сути вопроса - рекурсивный вызов (а это именно рекурсия во втором варианте, причем бесконечная) - так или иначе будет засирать стек, память и пр.
Стандартно такая задача решается использованием шедулера (в норме), либо вызова функции в бесконечном цикле (изврат).
83K
08 августа 2012 года
Deroy
3 / / 15.06.2012
потребляемая память растет из-за того что вы вызываете сам скрипт внутри себя (используете рекурсию, фактически создавая его новый экземпляр)
каждый предыдущий экземпляр не исчезнет пока каждый из вызванных внутри экземпляров не вернет значение или void (проще говоря не закончится)
используя unset() вы лишь временно снижаете кол-во используемой памяти.

для предотвращения утечки памяти не вызывайте скрипт внутри себя а в цикле вызывайте его до тех пор пока он не вернет значение выхода из цикла:

Код:
public function run(){
        if($this->_isStop()) return FALSE;
        $res=Query('SELECT * FROM table');
        while($row=mysql_fetch_assoc($res)){
            foreach($row AS $k=>$r){
                $r==$row[$k];
            }
        }
        unset($res,$row,$k,$r);
        sleep(5);
        return TRUE;
    }
Окружение где вызывается метод:

 
Код:
//some code before
while($eoc){
    $eoc = $object->run();
}
//some code after
Хотя вообще нет практической разницы как писать как ваш первый вариант или как мой - PHP-язык однопоточный пока у вас этот метод в цикле не отработает дальше не случится ничего.

а если нужно переносить результаты работы от одной итерации цикла к другой используйте ключевое слово static при объявлении переменных которые должны существовать постоянно и хранить в себе результаты работы метода run()

но лучше использовать Cron или другой шедулер как сказал kot_
277
08 августа 2012 года
arrjj
1.7K / / 26.01.2011
Ну а судя по тому что у тебя там что то из бд выбирается проще триггерами и UDF реализовать.
714
08 августа 2012 года
clgs
226 / / 29.10.2008
Вот пытаемся отказаться от использования планировщика для конкретной задачи. В общем я понял свою ошибку, буду пробовать. Спасибо.
1
09 августа 2012 года
kot_
7.3K / / 20.01.2000
Цитата: clgs
Вот пытаемся отказаться от использования планировщика для конкретной задачи


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

271
11 августа 2012 года
MrXaK
721 / / 31.12.2002
Для начала стоит демонизироваться самим (pcntl_fork()+exit(1) в основном скрипте), потом запускаем бесконечный цикл, в котором спим и вызываем воркера (ваша выборка, оформленная в отдельную функцию), в воркере снова форкаемся, из него выходим exit()'ом.
1
11 августа 2012 года
kot_
7.3K / / 20.01.2000
Цитата: MrXaK
Для начала стоит демонизироваться самим (pcntl_fork()+exit(1) в основном скрипте), потом запускаем бесконечный цикл, в котором спим и вызываем воркера (ваша выборка, оформленная в отдельную функцию), в воркере снова форкаемся, из него выходим exit()'ом.


можно и так.
Но это по сути создание собственного велосипеда с квадратными колесами.
Основные проблемы при этом
1) память таки жрется все равно;
2) создаем себе проблемы на пятую точку - ибо будет работать не во всех случаях - зависит от настроек безопасности и способа запуска самого пхп.
3) очень сильно зависит от кривизны рук исполнителя и от навыков системного программирования вообще.
но впрочем тут решать ТС - ему виднее.

271
12 августа 2012 года
MrXaK
721 / / 31.12.2002
Вообще при использовании exit() зендовский сборщик мусора должен всё убирать, а всё что жрёт память у нас процессе, который завершается exit'ом.
714
16 августа 2012 года
clgs
226 / / 29.10.2008
т.е. рекомендуете после каждого завершения процедуры делать exit, перехватывать его и опять запускать процедуры. Я правильно понял?
277
16 августа 2012 года
arrjj
1.7K / / 26.01.2011
Цитата: clgs
т.е. рекомендуете после каждого завершения процедуры делать exit, перехватывать его и опять запускать процедуры. Я правильно понял?


The cake is a lie! Не слушай их. Они тебе предлагают в скрипте вместо цикла делать форк. Как то так насколько я понял:

Код:
<?php
$pid=0;
do
{
switch ($pid ) {
      case -1:
         // @fail
         die('Fork failed');
         break;

      case 0:
//Делаем сови дела
         break;
      default:
            exit(0);
         break;
   }
while(($pid=pcntl_fork())==0)
}
?>
ИМХО какой то изврат
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог