про реализацию таймаута на php

Discussion in 'PHP' started by null_access, 26 Apr 2007.

  1. null_access

    null_access Elder - Старейшина

    Joined:
    31 Jan 2005
    Messages:
    128
    Likes Received:
    6
    Reputations:
    0
    люди, есть скрипт,там цикл, в конце цикла скрипт вызывает функцию, та функция работает с сокетами и я вынес её в отдельный файл а в основном скрипте прописсал include(файл.php), нужно поставить таймаут как то на функцию целиком эту, и чтобы основной скрипт продолжал работать если функция прервалась по таймауту т.е. цикл продолжал бы выполняться, а если написсать set_time_limit(xx); в файле с функцией, то весь скрипт перестаёт работать, а нне только функция.

    вопросик, как прерывать функцию по условию что время её работы истекло, и продолжать выполнение php?
     
  2. SMiX

    SMiX Elder - Старейшина

    Joined:
    25 Jul 2005
    Messages:
    227
    Likes Received:
    55
    Reputations:
    29
    1 вариант - pcntl_fork()
    2 - напрямую через системные вызовы() [удобнее popen() proc_open()]
     
    1 person likes this.
  3. null_access

    null_access Elder - Старейшина

    Joined:
    31 Jan 2005
    Messages:
    128
    Likes Received:
    6
    Reputations:
    0
    начал делать с помощью proc_open:
    Code:
    <?php
    set_time_limit(0);
    for($t=0;$t<100000;$t++) //цикл
    {
    
    $descriptorspec = array(
       0 => array("pipe", "r"),  // stdin это канал, из которого потомок будет читать
       1 => array("pipe", "w"),  // stdout это канал, в который потомок будет записывать
       2 => array("file", "/tmp/error-output.txt", "a"), // stderr это файл для записи
    );
    $process = proc_open("php", $descriptorspec, $pipes);
    
    if (is_resource($process)) {
    
        // $pipes выглядит теперь примерно так:
        // 0 => записываемый дескриптор, соединённый с дочерним stdin
        // 1 => читаемый дескриптор, соединённый с дочерним stdout
        // Любой вывод ошибки будет присоединён к /tmp/error-output.txt
    
        fwrite($pipes[0], func_needed_timeout($zz));
        fclose($pipes[0]);
    
        while(!feof($pipes[1])) {
            echo fgets($pipes[1], 1024);
        }
        fclose($pipes[1]);
        // Важно, чтобы вы закрыли любые каналы до вызова
        // proc_close, чтобы исключить тупиковую блокировку
        $return_value = proc_close($process);
    
        echo "command returned $return_value\n";
    }
    
    }
    
    function function_needed_timeout($zz)
    {
    set_time_limit(10);
    //здесь дописать код ункции нуждающаяся в прерывании по таймауту
    }
    ?>
    Думал set_time_limit если установить на родительский и дочерний процессы как в примере, всё будет работать, а нет, всё равно прерывается работа всего скрипта.
    Need help, как принудительно прерывать функцию под названием function_needed_timeout($zz) через заданный промежток времени?
     
  4. SMiX

    SMiX Elder - Старейшина

    Joined:
    25 Jul 2005
    Messages:
    227
    Likes Received:
    55
    Reputations:
    29
    В данном случае таймаут выставляй не с помощью set_time_limit(), а контроллируй время выполнения скрипта(`потока`) главным скриптом.
     
  5. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,193
    Reputations:
    252
    sleep() ? :D
     
  6. SMiX

    SMiX Elder - Старейшина

    Joined:
    25 Jul 2005
    Messages:
    227
    Likes Received:
    55
    Reputations:
    29
    Причем здесь sleep()?
     
    2 people like this.
  7. Developer

    Developer Elder - Старейшина

    Joined:
    3 May 2006
    Messages:
    152
    Likes Received:
    25
    Reputations:
    10
    По сабжу:

    Таймаут на функцию - значит таймаут на соединение сокета. Функция fsockopen принимает пятый параметр timeout, по истечении которого хост считается мертвым.

    Таймаут на скрипт - это set_time_limit, определующий максимально допустимое время выполнения скрипта. Для неограниченного выполнения - set_time_limit(0). Функция не работает с Safe Mode.
    Так же не забывает про то, что у Apache есть свой таймаут и подвисшие процессы он убивает самостоятельно. Так что если хотим работы скрипта "пока не исполнится" - запускаем его через exec/system/popen и т.п.
     
  8. Developer

    Developer Elder - Старейшина

    Joined:
    3 May 2006
    Messages:
    152
    Likes Received:
    25
    Reputations:
    10
    А вот так я запускаю скрипты в фоновом режиме:

    PHP:
    if (file_exists('is_running.txt')) {
        
    writeFile(time() . '>BStart' EOL'is_running.txt''a');
        ... 
    Тут идем сам скрипт
        unlink
    ('is_running.txt');
        exit;
    }

    if (isset(
    $_GET['start'])) {
        
    writeFile(time() . '>SStart' EOL'is_running.txt''w');
        
    $fp popen('php -f ' __FILE__ ' &''r');
        
    pclose($fp);
        echo 
    'Script started!';
    }
    Для тех, кому интерестно, что же все-таки за функция writeFile:

    PHP:
    function writeFile($data$file$type 'a')
    {
        
    $fp fopen($file$type);
        
    flock($fp2);
        
    fwrite($fp$data);
        
    flock($fp3);
        
    fclose($fp);
    }
     
    1 person likes this.
  9. Developer

    Developer Elder - Старейшина

    Joined:
    3 May 2006
    Messages:
    152
    Likes Received:
    25
    Reputations:
    10
    EOL:

    PHP:
    define('EOL'"\n");
    ЗЫ: Жаль на форуме не дополняются сообщения, не привычно.
     
  10. null_access

    null_access Elder - Старейшина

    Joined:
    31 Jan 2005
    Messages:
    128
    Likes Received:
    6
    Reputations:
    0
    Это по теории так, а на практике я имею такую ситуацию, что такой вот код являющийся частью функции:
    PHP:
    $fp=fsockopen($HostName$HostPort$errno$errstr30); 

    if (!
    $fp//Если соединение прошло неуспешно, выводим сообщение об ошибке ставшей причиной проблемы.
        

        echo 
    "$errstr ($errno)<br />\n"
        } 
    else         
    //Если соединение прошло успешно, то формируем пакет запрса к серверу. 
        

        
    $out  "GET .......\r\n"
        ................

        
    stream_set_timeout($fp30);     //Выставляем таймау на операции с сервером. Если в течение заданного отрезка времени не происходит никакого
                                    //обмена данными, то считаем чо соединение подвисло и обрываем его. 

        
    fputs($fp$out);         //Передаем ранее сформированный пакт данных серверу. 

       //получаем ответ сервера в переменную $Page 
            
    $Page=""
            while (!
    feof($fp)) 
                { 
                
    $Page.=fgets($fp); 
                } 
    так вот, такой вод код, очень часто подвисает на неограниченное время, и только поэтому я стартанул эту темку.)
    пасибки большое, что пишите свои мысли по этому поводу, пока ещё не сделал что нужно, учусь типа.) :cool:
     
    1 person likes this.
  11. SMiX

    SMiX Elder - Старейшина

    Joined:
    25 Jul 2005
    Messages:
    227
    Likes Received:
    55
    Reputations:
    29
    Это может произойти, если сокет все-таки открылся, но очень медленный. И запрос идет туда с очень мелкой скоростью - таймаут сокета тут не поможет(разве что очень маленький). Сталкивался с такой ситуацией.
     
  12. Developer

    Developer Elder - Старейшина

    Joined:
    3 May 2006
    Messages:
    152
    Likes Received:
    25
    Reputations:
    10
    PHP:
    stream_set_timeout($fp30);
    Не работал с этой функций, но мне кажется что она выставляет таймаут на каждую операцию, а не на все. Соответственно подвиснет на ограниченное, но оч большое время про плохом коннекте.