Run parallel process in PHP

Asked

Viewed 3,923 times

8

I own a Web service that is consumed by some applications. On the Web service there must be the use of API of Amazon and perform a process whenever a record change is made via Web service.

Initially I thought to run the process with Amazon at the same time as it responds to the user. The fact is that the Amazon service tends to take longer compared to the response from Web service applications, which could result in a high user response time.

In this case I thought to run in Threads, so whenever a request was sent to Web service, it would start in parallel the connection with Amazon. Only there are resource restrictions on the server (Locaweb) and I am not allowed to install add-ons (PECL).

<?php

class workerThread extends Thread {
    public function __construct($i){
        $this->i=$i;
    }

    public function run(){
        while(true){
            echo $this->i;
            sleep(1);
        }
    }
}

for($i=0;$i<50;$i++){
    $workers[$i]=new workerThread($i);
    $workers[$i]->start();
}

?>

Another way I thought of doing it would be to execute one Curl, but from what I’ve seen, the response time is the same as executing the process on the same line Web service.

So master gurus, with the PHP, it is possible to execute this communication with the Amazon in the background and the response to the user is sent in the standard time of the Web service to avoid a very high response time?

  • The most traditional way would be to use scheduled tasks (with cron), which run from time to time and handle a queue of what needs to be done in the webservice.

  • the main script needs to wait for completion of parallel processes or not?

  • No need to wait @Sanction

2 answers

9


To run a parallel process, follow the steps below.

You mentioned that the hosting is in Locaweb and the function exec is locked on their Windows servers. I’ve seen other companies block this function. So this answer only works on Linux. For Windows it is possible to adapt with code of that reply (in English).

Create a php file with the process that should run in the background, in this example will be thread.php

In the file that will start thread include:

exec('php diretorio/thread.php >> diretorio_logs/arquivo_de_log.log 2>&1 &');

The function exec executes command line to string passed as parameter.

The operator >> saves all that thread.php flaunt echo (printf, etc.) in the specified file. The part 2>&1 redirects the error output (stderr) for the standard output (stdout), then anything that is displayed by thread.php will be saved in arquivo_de_log.log, including possible errors.

If the exit of thread.php can be discarded use only:

exec('php diretorio/thread.php &');

The & in the end is responsible for initiating the execution of the process in the background. With this modifier, the command is executed and the process that called the command nay awaits its completion.


there is a PHP extension for process control that can also be used: http://php.net/manual/en/book.pcntl.php

  • I am familiar with shell, linux and its commands, and did not pay attention to this detail, really I can run shell commands via php. I believe that your solution depends on putting the following line in the file header: #!/usr/bin/php -q. I’m right @Sanction?

  • @touchmx saw the need for this header only to execute PHP commands in CGI mode on this wiki page of Locaweb, when using this process it was not necessary to include the header (Ubuntu environment 14.04)

4

A routine that executes processes in the background:

class Background
{

    /*
    $cmd -> A linha de comando a executar.
    $opt -> Opção de parâmetros para o ambiente onde executa o script.
    */
    public static function Call($cmd, $opt = 'start')
    {

        if (stripos(php_uname('s'), 'windows') !== false) {
            /*
            Condições de parâmetros para ambiente Windows.
            */
            switch ($opt) {
                default:
                case 'start':
                    $prefix = 'start /B '; // Esse aqui é o padrão, pois é compatível com as versões mais recentes do Windows.
                    $sufix = '';
                    break;
                case 'nul':
                    $prefix = '';
                    $sufix = ' > NUL 2> NUL';
                    break;
            }
        } else {
            /*
            Opções para ambiente *nix. (isso inclui os-x)
            Normalmente o sufixo ` &` é compatível com diversas distribuições Linux. Esse parâmetro diz ao sistema operacional executar em background.
            */
            switch ($opt) {
                default:
                case '&':
                    $prefix = '';
                    $sufix = ' &';
                    break;
                case 'dev-null':
                    $prefix = '';
                    $sufix = ' > /dev/null 2>/dev/null &';
                    break;
            }
        }

        exec(sprintf('%s%s%s', $prefix, $cmd, $sufix));

        return null;
    }

}

define('PHP_PATH', '/local/do/binario/php');

echo 'start '.microtime(true);
Background::Call(PHP_PATH.' "/local/de/um/arquivo.php"');
Background::Call(PHP_PATH.' "/local/de/um/arquivo.php"');
Background::Call(PHP_PATH.' "/local/de/um/arquivo.php"');
echo PHP_EOL.'end '.microtime(true);

php file.

<?php

/*
Fecha o output, ou seja, faz com que o script que invocou, não fique esperando por uma resposta.
*/
fclose(STDOUT);

/*
Daqui em diante, pode fazer o que bem entender.
Claro, esteja ciente de que tudo aqui está sendo executado em ambiente CLI (Command Line Interface).

Vamos fazer uma simulação e testar se está funcionando.
*/

file_put_contents('background.txt', 'start '.microtime(true).PHP_EOL, FILE_APPEND);
sleep(5); // espera 5 segundos
file_put_contents(BASE_DIR.'background.txt', 'end '.microtime(true).PHP_EOL, FILE_APPEND);

About the asynchronous execution routine

There is no process control. Basically an execution command is sent by the function exec(), that combined with some parameters ignores the return of a response. Thus, asynchronous executions.

Combinations vary by environment, so be aware that it is not enough to just copy the code and think it will work like magic.

In the method Call() class Background, just add new parameters if necessary.

Example:

            /*
            Opções para ambiente *nix. (isso inclui os-x)
            Normalmente o sufixo ` &` é compatível com diversas distribuições Linux. Esse parâmetro diz ao sistema operacional executar em background.
            */

            switch ($opt) {
                default:
                case '&':
                    $prefix = '';
                    $sufix = ' &';
                    break;
                case 'dev-null':
                    $prefix = '';
                    $sufix = ' > /dev/null 2>/dev/null &';
                    break;
                case 'dev-null2':
                    $prefix = '';
                    $sufix = ' /dev/null 2>&1 &';
                    break;
                case 'outro-nome-como-quiser':
                    $prefix = '';
                    $sufix = ' /algum/comando/diferente/que/funcione/num/ambiente/especifico';
                    break;
            } 

The script is simple, clean, easy to understand. It does not depend on third party libraries.

  • Sensational! Thank you

Browser other questions tagged

You are not signed in. Login or sign up in order to post.