Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use PCNTL to call a php function in parallel

I have around 10 different requests for different servers and used to get the response sequentially in respective to the function call in my website.

Now, I want to call my function in parallel for different server request. Once I get the first response from any of the servers, then want to stop the the remaining processes.

Currently I am calling my function like so:

my_launch(1);
my_launch(2);
my_launch(3);
my_launch(4);
my_launch(5);
my_launch(6);
my_launch(7);
my_launch(8);
my_launch(9);
my_launch(10);  

This executes sequentially; how can I run this code in parallel using PCNTL?

like image 361
Jeet Singh Avatar asked Jan 27 '26 15:01

Jeet Singh


1 Answers

About PCNTL availibility

PHP has some PCNTL features built in but they are not enabled by default.

From php.net pcntl installation instructions:

You have to compile the CGI or CLI version of PHP with --enable-pcntl configuration option when compiling PHP to enable Process Control support.


Regarding parallelization

If you know the number of cores on your machine, then I would suggest dividing the work into that many divisions. Process control only works on *nix-like systems, so you probably have the nproc command available:

$numberOfProcessors = `nproc`;

You fork to get the proper number of processes running, divide the work between them and off you go. Dividing the work might be difficult, but I'm sure you'll figure it out.


Code dump

I was feeling generous so I went ahead and coded most of it for you. Be sure to understand it because it isn't quite finished.

Notes:

  • Grabs the number of available processors by calling nproc, so if you don't have that utility you should replace it with the number of processes you want to make.
  • If you have more processors available than requested iterations it will not break. It simply uses fewer processors.
  • If the number of processes doesn't divide evenly into the number of the iterations, the parent process will pick up the remaining iterations.
  • Does not stop after the first result is available. In order to do this, you will need to have one process per iteration. The main process should call pcntl_wait for when the first one finishes and kill the others.

Code:

$procs = `nproc`;
$iterations = 10;
$pids = array();
$iproc = -1;

if ($procs > $iterations) {
    $procs = $iterations;
}

function my_launch($i, $proc) {
    echo "Process $proc ran iteration $i.\n";
}

$pid = 0;
for ($i = 0; $i < $procs; $i++) {
    $pid = pcntl_fork();
    if ($pid > 0) {
        // I am the parent process
        $pids[$pid] = $pid;

    } elseif ($pid == -1) {
        //error occurred, use available processes only
        $nproc = $i;
        break;

    } else {
        //I am the child process.
        $iproc = $i;
        break;
    }
}

$nproc = !empty($nproc) ? $nproc : $procs;

if ($nproc == 0) {
    echo "NOTICE: Process could not be forked; proceeding in serial.\n";
    for ($i = 0; $i < $iterations; $i++) {
        my_launch($i, $iproc);
    }
    exit;
}

if ($nproc != $procs) {
    echo "NOTICE: Only using $nproc processes out of the hoped $procs.\n";
}

$iterationsPerProcess = (int) ($iterations / $nproc);

// children do the main work.
if ($pid == 0) {
    $stopAt = $iterationsPerProcess * ($iproc + 1);

    for ($i = ($iproc * $iterationsPerProcess); $i < $stopAt; $i++) {
        my_launch($i, $iproc);
    }
}

if ($pid > 0) {
    // parent process picks up the remainder of the work
    $i = $nproc * $iterationsPerProcess;
    for (; $i < $iterations; $i++) {
        my_launch($i, "Main");
    }

    //wait for children to finish
    $status = -1;
    foreach ($pids as $createdIndex => $pid) {
        pcntl_waitpid($pid, $status);
    }
}
like image 168
Levi Morrison Avatar answered Jan 30 '26 05:01

Levi Morrison



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!